<!DOCTYPE html>


<html lang="en">
  

    <head>
      <meta charset="utf-8" />
        
      <meta name="description" content="時光的个人博客" />
      
      <meta
        name="viewport"
        content="width=device-width, initial-scale=1, maximum-scale=1"
      />
	  <meta name="referrer" content="no-referrer" />

      <title> 時光</title>
  <meta name="generator" content="hexo-theme-ayer">
      
      <link rel="shortcut icon" href="/favicon.ico" />
       
<link rel="stylesheet" href="/dist/main.css">

      
<link rel="stylesheet" href="/css/fonts/remixicon.css">

      
<link rel="stylesheet" href="/css/custom.css">
 
      <script src="https://cdn.staticfile.org/pace/1.2.4/pace.min.js"></script>
       
 

      <link
        rel="stylesheet"
        href="https://cdn.jsdelivr.net/npm/@sweetalert2/theme-bulma@5.0.1/bulma.min.css"
      />
      <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11.0.19/dist/sweetalert2.min.js"></script>

      <!-- mermaid -->
      
      <style>
        .swal2-styled.swal2-confirm {
          font-size: 1.6rem;
        }
      </style>
    <link rel="alternate" href="/atom.xml" title="時光" type="application/atom+xml">
</head>
  </html>
</html>


<body>
  <div id="app">
    
      
    <main class="content on">
      
<section class="cover">
    
      
      <a class="forkMe" href="https://github.com/Shen-Yu/hexo-theme-ayer"
        target="_blank"><img width="149" height="149" src="/images/forkme.png"
          class="attachment-full size-full" alt="Fork me on GitHub" data-recalc-dims="1"></a>
    
  <div class="cover-frame">
    <div class="bg-box">
      <img src="/images/cover1.jpg" alt="image frame" />
    </div>
    <div class="cover-inner text-center text-white">
      <h1><a href="/">時光</a></h1>
      <div id="subtitle-box">
        
        <span id="subtitle"></span>
        
      </div>
      <div>
        
      </div>
    </div>
  </div>
  <div class="cover-learn-more">
    <a href="javascript:void(0)" class="anchor"><i class="ri-arrow-down-line"></i></a>
  </div>
</section>



<script src="https://cdn.staticfile.org/typed.js/2.0.12/typed.min.js"></script>


<!-- Subtitle -->

  <script>
    try {
      var typed = new Typed("#subtitle", {
        strings: ['面朝大海，春暖花开', '愿你一生努力，一生被爱', '想要的都拥有，得不到的都释怀'],
        startDelay: 0,
        typeSpeed: 200,
        loop: true,
        backSpeed: 100,
        showCursor: true
      });
    } catch (err) {
      console.log(err)
    }
  </script>
  
<div id="main">
  <section class="outer">
  
  
  

<div class="notice" style="margin-top:50px">
    <i class="ri-heart-fill"></i>
    <div class="notice-content" id="broad"></div>
</div>
<script type="text/javascript">
    fetch('https://v1.hitokoto.cn')
        .then(response => response.json())
        .then(data => {
            document.getElementById("broad").innerHTML = data.hitokoto;
        })
        .catch(console.error)
</script>

<style>
    .notice {
        padding: 20px;
        border: 1px dashed #e6e6e6;
        color: #969696;
        position: relative;
        display: inline-block;
        width: 100%;
        background: #fbfbfb50;
        border-radius: 10px;
    }

    .notice i {
        float: left;
        color: #999;
        font-size: 16px;
        padding-right: 10px;
        vertical-align: middle;
        margin-top: -2px;
    }

    .notice-content {
        display: initial;
        vertical-align: middle;
    }
</style>
  
  <article class="articles">
    
    
    
    
    <article
  id="post-搭建自定义导航网站"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2023/12/05/%E6%90%AD%E5%BB%BA%E8%87%AA%E5%AE%9A%E4%B9%89%E5%AF%BC%E8%88%AA%E7%BD%91%E7%AB%99/"
    >搭建自定义导航网站</a> 
</h2>
 

      
    </header>
     
    <div class="article-meta">
      <a href="/2023/12/05/%E6%90%AD%E5%BB%BA%E8%87%AA%E5%AE%9A%E4%B9%89%E5%AF%BC%E8%88%AA%E7%BD%91%E7%AB%99/" class="article-date">
  <time datetime="2023-12-05T14:31:06.444Z" itemprop="datePublished">2023-12-05</time>
</a> 
  <div class="article-category">
    <a class="article-category-link" href="/categories/%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B/">安装教程</a>
  </div>
   
    </div>
      
    <div class="article-entry" itemprop="articleBody">
       
  <p>免费版地址<br><a target="_blank" rel="noopener" href="https://www.iotheme.cn/store/webstack.html">https://www.iotheme.cn/store/webstack.html</a></p>
<p>付费版购买地址<br><a target="_blank" rel="noopener" href="https://www.iotheme.cn/store/onenav.html">https://www.iotheme.cn/store/onenav.html</a></p>
<p>Webstack项目地址：<a target="_blank" rel="noopener" href="https://github.com/HCLonely/hexo-theme-webstack">https://github.com/HCLonely/hexo-theme-webstack</a></p>
<p>其他主题推荐</p>
<p>TwoNav主题：<a target="_blank" rel="noopener" href="https://github.com/tznb1/TwoNav">https://github.com/tznb1/TwoNav</a></p>
<h1 id="一、安装宝塔面板"><a href="#一、安装宝塔面板" class="headerlink" title="一、安装宝塔面板"></a>一、安装宝塔面板</h1><p>宝塔官网：<a target="_blank" rel="noopener" href="https://www.bt.cn/new/download.html">https://www.bt.cn/new/download.html</a></p>
<h2 id="Centos安装脚本"><a href="#Centos安装脚本" class="headerlink" title="Centos安装脚本"></a><strong>Centos安装脚本</strong></h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum install -y wget &amp;&amp; wget -O install.sh https://download.bt.cn/install/install_6.0.sh &amp;&amp; sh install.sh ed8484bec</span><br></pre></td></tr></table></figure>

<h2 id="Ubuntu-x2F-Deepin安装脚本"><a href="#Ubuntu-x2F-Deepin安装脚本" class="headerlink" title="Ubuntu&#x2F;Deepin安装脚本"></a><strong>Ubuntu&#x2F;Deepin安装脚本</strong></h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget -O install.sh https://download.bt.cn/install/install-ubuntu_6.0.sh &amp;&amp; sudo bash install.sh ed8484bec</span><br></pre></td></tr></table></figure>

<h2 id="Debian安装脚本"><a href="#Debian安装脚本" class="headerlink" title="Debian安装脚本"></a><strong>Debian安装脚本</strong></h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget -O install.sh https://download.bt.cn/install/install-ubuntu_6.0.sh &amp;&amp; bash install.sh ed8484bec</span><br></pre></td></tr></table></figure>

<h2 id="万能安装脚本"><a href="#万能安装脚本" class="headerlink" title="万能安装脚本"></a><strong>万能安装脚本</strong></h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">if [ -f /usr/bin/curl ];then curl -sSO https://download.bt.cn/install/install_panel.sh;else wget -O install_panel.sh https://download.bt.cn/install/install_panel.sh;fi;bash install_panel.sh ed8484bec</span><br></pre></td></tr></table></figure>

<h2 id="国产龙芯架构安装脚本（其他CPU请勿使用）"><a href="#国产龙芯架构安装脚本（其他CPU请勿使用）" class="headerlink" title="国产龙芯架构安装脚本（其他CPU请勿使用）"></a><strong>国产龙芯架构安装脚本（其他CPU请勿使用）</strong></h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget -O install_panel.sh https://download.bt.cn/install/0/loongarch64/loongarch64_install_panel.sh &amp;&amp; bash install_panel.sh ed8484bec</span><br></pre></td></tr></table></figure>

<p>安装完成后会提示访问地址及用户密码</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231206214426925-781740990.png" alt="image-20231206214422816"></p>
<p>输入 <code>bt </code> 可查看宝塔面板相关命令</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231212154329963-803845647.png" alt="image-20231212154330290"></p>
<h1 id="二、安装基础服务"><a href="#二、安装基础服务" class="headerlink" title="二、安装基础服务"></a>二、安装基础服务</h1><p>需安装 Nginx、Mysql（建议5.7及以上版本）、PHP</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231205225047071-1102407633.png" alt="image-20231205225027722"></p>
<h2 id="三、安装wordpress服务"><a href="#三、安装wordpress服务" class="headerlink" title="三、安装wordpress服务"></a>三、安装wordpress服务</h2><h2 id="1、设置域名"><a href="#1、设置域名" class="headerlink" title="1、设置域名"></a>1、设置域名</h2><p>安装前可以先配置下域名，添加一条www的A记录</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231207130426491-2053203062.png" alt="image-20231207130419098"></p>
<h2 id="2、添加站点"><a href="#2、添加站点" class="headerlink" title="2、添加站点"></a>2、添加站点</h2><p>在宝塔面板添加站点，域名用刚才添加的域名，没有域名可直接用主机ip</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231207130507881-1515336514.png" alt="image-20231207130505865"></p>
<p>站点创建成功后会再次弹框确认数据账号及密码，可写个文档记录起来</p>
<h2 id="3、上传资源文件"><a href="#3、上传资源文件" class="headerlink" title="3、上传资源文件"></a>3、上传资源文件</h2><p>点击根目录链接进入根目录</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231207130649488-1609283702.png" alt="image-20231207130647519"></p>
<p>清空该目录内所用文件并上传wordpress安装文件</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231207130746013-1540082662.png" alt="image-20231207130743255"></p>
<p>上传完成后将文件进行解压</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231207130836253-302310668.png" alt="image-20231207130833960"></p>
<p>解压后可以将原来的压缩包删除，然后将解压后的所有文件全选剪切到根目录</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231207130940939-746758842.png" alt="image-20231207130938113"></p>
<p>粘贴后可以将原来的wordpress空目录删除，所有文件在站点根目录同一级</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231207131106123-1424813966.png" alt="image-20231207131103899"></p>
<p>此时通过域名及端口已能正常访问</p>
<p>若不能正常访问许检查80、443端口是否冲突，安全组是否放行所需端口，Nginx服务启动是否正常</p>
<p>若无以上错误，可尝试申请ssl证书后重新访问</p>
<h2 id="4、开启伪静态"><a href="#4、开启伪静态" class="headerlink" title="4、开启伪静态"></a>4、开启伪静态</h2><p>设置伪静态能提高网站检索权重</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231207131535847-2120931197.png" alt="image-20231207131532237"></p>
<h2 id="5、设置SSL证书"><a href="#5、设置SSL证书" class="headerlink" title="5、设置SSL证书"></a>5、设置SSL证书</h2><p>申请 <code>Let&#39;s Encrypt</code> 免费证书</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231207131712914-292456289.png" alt="image-20231207131710560"></p>
<p>申请成功如下所示</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231212153257314-251334608.png" alt="image-20231212153257736"></p>
<p>若证书申请失败，如图所示</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231212153504902-1087186006.png" alt="image-20231212153505277"></p>
<p>仍需检查 所需端口是否被占用，一般为80，443端口</p>
<p>另外需检查Nginx配置是否添加站点server配置，若未添加需手动添加</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231212152858112-1453010230.png" alt="image-20231212152858330"></p>
<h1 id="三、安装wordpress"><a href="#三、安装wordpress" class="headerlink" title="三、安装wordpress"></a>三、安装wordpress</h1><h2 id="1、选择使用语言"><a href="#1、选择使用语言" class="headerlink" title="1、选择使用语言"></a>1、选择使用语言</h2><p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231210183513480-1920467402.png" alt="image-20231210183513608"></p>
<h2 id="2、关联数据库"><a href="#2、关联数据库" class="headerlink" title="2、关联数据库"></a>2、关联数据库</h2><p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231210183945593-1548832551.png" alt="image-20231210183945886"></p>
<h2 id="3、执行安装程序"><a href="#3、执行安装程序" class="headerlink" title="3、执行安装程序"></a>3、执行安装程序</h2><p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231210184331574-24565961.png" alt="image-20231210184331851"></p>
<h2 id="4、设置站点信息"><a href="#4、设置站点信息" class="headerlink" title="4、设置站点信息"></a>4、设置站点信息</h2><p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231210184425019-425292561.png" alt="image-20231210184425231"></p>
<p>安装完成后会自动跳转到后台管理界面，管理界面地址： <code>域名或ip/wp-admin</code></p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231210184732005-547247474.png" alt="image-20231210184732241"></p>
<h1 id="四、导航站主题配置"><a href="#四、导航站主题配置" class="headerlink" title="四、导航站主题配置"></a>四、导航站主题配置</h1><h2 id="1、安装主题"><a href="#1、安装主题" class="headerlink" title="1、安装主题"></a>1、安装主题</h2><p>外观 -&gt; 添加新主题 -&gt; 上传主题 -&gt; 上传主题</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231211235404755-736567806.png" alt="image-20231211235358818"></p>
<p>安装好后如下所示，点击启用即可</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231212001313462-1821521391.png" alt="image-20231212001308445"></p>
<p>启用后会多出 网址 一栏</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231212001517506-1918188951.png" alt="image-20231212001500908"></p>
<h2 id="2、安装插件"><a href="#2、安装插件" class="headerlink" title="2、安装插件"></a>2、安装插件</h2><p>插件 &#x3D;&gt; 添加新插件 &#x3D;&gt; 上传插件，需安装 <code>redis-cache</code>  和 <code>wp-rocket</code> 插件，先不要启用</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231212001657276-1669673131.png" alt="image-20231212001641534"></p>
<p>宝塔面板 &#x3D;&gt; 软件商店 &#x3D;&gt;  已安装  &#x3D;&gt; PHP &#x3D;&gt; 设置 &#x3D;&gt; 安装拓展  安装 <code>opcache</code> 和  <code>redis</code> 拓展 </p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231212002242404-1512309611.png" alt="image-20231212002226489"></p>
<p>插件 &#x3D;&gt; 已安装插件 &#x3D;&gt;  启用刚才上传的两个插件</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231212002953247-1411174404.png" alt="image-20231212002946507"></p>
<h2 id="3、修改链接结构"><a href="#3、修改链接结构" class="headerlink" title="3、修改链接结构"></a>3、修改链接结构</h2><p>设置 &#x3D;&gt; 固定连接 &#x3D;&gt;  固定链接结构 &#x3D;&gt; 自定义结构，设置为 <code>/%post_id%.html</code></p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231212003351689-2050304142.png" alt="image-20231212003336337"></p>
<p>此时使用ip 或者域名就可以访问了</p>
<p><img src="C:/Users/shiguang/AppData/Roaming/Typora/typora-user-images/image-20231212003701150.png" alt="image-20231212003701150"></p>
<h2 id="4、基本功能"><a href="#4、基本功能" class="headerlink" title="4、基本功能"></a>4、基本功能</h2><p>网址 &#x3D;&gt; 网址分类</p>
<p>填写名称，描述，选择菜单图标，添加新网址目录</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231212010114639-1719071349.png" alt="image-20231212010057790"></p>
<p>网址 &#x3D;&gt; 添加网址</p>
<p>填写标题，描述，网址连接，图标路径，选择网址分类目录，发布即可</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231212004857060-639422935.png" alt="image-20231212004852382"></p>
<p>添加后如下所示</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231212005123156-942049595.png" alt="image-20231212005108353"></p>
<p>其他更多配置可在主题设置进行调整</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231212005428556-1422541523.png" alt="image-20231212005413041"></p>
<h2 id="5、移除Fork-me-on-GitHub图标"><a href="#5、移除Fork-me-on-GitHub图标" class="headerlink" title="5、移除Fork me on GitHub图标"></a>5、移除<code>Fork me on GitHub</code>图标</h2><p>回到宝塔面板，进入站点根目录，找到 <code>/templates/header-banner.php</code> 文件，双击进行编辑</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231212005813219-1522323104.png" alt="image-20231212005758285"></p>
<p>删除最后一段a链接保存即可</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231212005935545-237471220.png" alt="image-20231212005929617"></p>
 
      <!-- reward -->
      
    </div>
    

    <!-- copyright -->
    
    <footer class="article-footer">
       
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/wordpress/" rel="tag">wordpress</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/%E5%AE%9D%E5%A1%94%E9%9D%A2%E6%9D%BF/" rel="tag">宝塔面板</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/%E5%AF%BC%E8%88%AA/" rel="tag">导航</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/%E5%BB%BA%E7%AB%99/" rel="tag">建站</a></li></ul>

    </footer>
  </div>

    
 
   
  
</article>

    
    <article
  id="post-免费领取云服务器"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2023/12/03/%E5%85%8D%E8%B4%B9%E9%A2%86%E5%8F%96%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8/"
    >免费领取云服务器</a> 
</h2>
 

      
    </header>
     
    <div class="article-meta">
      <a href="/2023/12/03/%E5%85%8D%E8%B4%B9%E9%A2%86%E5%8F%96%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8/" class="article-date">
  <time datetime="2023-12-03T12:58:54.090Z" itemprop="datePublished">2023-12-03</time>
</a> 
  <div class="article-category">
    <a class="article-category-link" href="/categories/%E7%99%BD%E5%AB%96%E7%A6%8F%E5%88%A9/">白嫖福利</a>
  </div>
   
    </div>
      
    <div class="article-entry" itemprop="articleBody">
       
  <h1 id="一、注册账号"><a href="#一、注册账号" class="headerlink" title="一、注册账号"></a>一、注册账号</h1><p>云服务器账号注册链接：<a target="_blank" rel="noopener" href="http://bit.ly/3GlfucW">http://bit.ly/3GlfucW</a></p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231203205035509-624210780.png" alt="image-20231203205020804"></p>
<p>可以在 <a target="_blank" rel="noopener" href="http://cpdc.chinapost.com.cn/web/">邮政名企网</a>查询邮编</p>
<h1 id="二、申请服务资源"><a href="#二、申请服务资源" class="headerlink" title="二、申请服务资源"></a>二、申请服务资源</h1><p>注册好后点击 <a target="_blank" rel="noopener" href="https://www.raksmart.com/home/article/details?a_id=242">活动链接</a> ，可以申请相关资源</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231203205139642-1511878459.png" alt="image-20231203205124271"></p>
<p>点击立即申请，自定义配置选择 1核2G</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231203205554758-253753913.png" alt="image-20231203205537229"></p>
<p>选择操作系统，此处我选择Ubuntu最新系统</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231203205915225-308709913.png" alt="image-20231203205910607"></p>
<p>宽带类型选择 <code>大陆优化</code>，点击继续</p>
<p>进入到订单界面，支付方式选择 <code>alipay</code> ，同意条款协议，点击结账 (不会真正付款)</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231203210153187-2132662155.png" alt="image-20231203210137471"></p>
<p>点击结账后会进入账单页面，无需继续操作</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231203210446267-1935352790.png" alt="image-20231203210431212"></p>
<p>回到客户中心，可以看到未付款的账单</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231203210540893-85140957.png" alt="image-20231203210525923"></p>
<p>点击 <code>查看服务</code></p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231203210710019-409391736.png" alt="image-20231203210655065"></p>
<p>继续点击 <code>新开工单</code></p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231203210747940-832804171.png" alt="image-20231203210732225"></p>
<p>主题填写 <code>申请免费云服务器</code>，信息可随意填写</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231203210843124-1811545548.png" alt="image-20231203210827102"></p>
<p>提交完成后如下</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231203210942682-1917242903.png" alt="image-20231203210938439"></p>
<p>可以回到客服中心查看我的工单</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231203211149079-241912483.png" alt="image-20231203211133251"></p>
<p>此时状态为售后处理中，等待处理完毕即可</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231203211216409-1569250275.png" alt="image-20231203211201737"></p>
<p>客服处理完毕后，状态会变为 <code>等您确认</code></p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231203214035765-209262970.png" alt="image-20231203214030587"></p>
<p>回到客服中心，点击我的服务，即可看到已有一台可用的服务器</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231203214212401-1494549329.png" alt="image-20231203214156827"></p>
<p>点击拦截可查看服务器详情</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231203214334434-1904347269.png" alt="image-20231203214313049"></p>
<h1 id="三、连接服务器"><a href="#三、连接服务器" class="headerlink" title="三、连接服务器"></a>三、连接服务器</h1><p>Windows开始菜单搜索 <code>PowerShell</code> </p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231203214450045-958990047.png" alt="image-20231203214427991"></p>
<p>输入 <code>ssh -p 端口 root@ip</code>，询问是否把该主机加入到Ip列表内，输入yes，然后输入密码即可</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231203214910011-1237942758.png" alt="image-20231203214851247"></p>
<p>如登录失败，许把当前端口添加到安全组</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231203215122861-1291129137.png" alt="image-20231203215118033"></p>
<p>安全组设置：<code>安全组</code>-&gt;<code>新建安全组</code>-&gt;<code>新增策略</code>-&gt;<code>规则方向（入）</code>-&gt;<code>协议（自定义TCP）</code>-&gt;<code>端口范围（填写端口号）</code>-&gt;<code>授权IP（0.0.0.0/0）</code></p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231203215402727-1835282132.png" alt="image-20231203215345983"></p>
<p>登录成功后，可以输入 <code>top</code> 命令查看当前服务器配置</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202312/2233039-20231203215554152-870391678.png" alt="image-20231203215537936"></p>
 
      <!-- reward -->
      
    </div>
    

    <!-- copyright -->
    
    <footer class="article-footer">
       
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/VPS/" rel="tag">VPS</a></li></ul>

    </footer>
  </div>

    
 
   
  
</article>

    
    <article
  id="post-Markdown语法使用表情符号"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2023/11/20/Markdown%E8%AF%AD%E6%B3%95%E4%BD%BF%E7%94%A8%E8%A1%A8%E6%83%85%E7%AC%A6%E5%8F%B7/"
    >Markdown语法使用表情符号</a> 
</h2>
 

      
    </header>
     
    <div class="article-meta">
      <a href="/2023/11/20/Markdown%E8%AF%AD%E6%B3%95%E4%BD%BF%E7%94%A8%E8%A1%A8%E6%83%85%E7%AC%A6%E5%8F%B7/" class="article-date">
  <time datetime="2023-11-20T06:06:57.113Z" itemprop="datePublished">2023-11-20</time>
</a> 
  <div class="article-category">
    <a class="article-category-link" href="/categories/%E5%B0%8F%E6%8A%80%E8%83%BD/">小技能</a>
  </div>
   
    </div>
      
    <div class="article-entry" itemprop="articleBody">
       
  <blockquote>
<p>语法代码</p>
</blockquote>
<p><strong>使用语法</strong>：<code>&amp;#x符号编码;</code> </p>
<p>其中符号编码可以从   <a target="_blank" rel="noopener" href="https://apps.timwhitlock.info/emoji/tables/unicode#block-4-enclosed-characters">Emoji Unicode Tables</a>  中获取到</p>
<p>例如我要用下面这个小火箭图标 它的编码是1F680 ，那么就是  <code>&amp;#x1F680;</code></p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231120215955198-1479885006.png" alt="image-20231120215954819"></p>
<blockquote>
<p>也可以直接复制</p>
</blockquote>
<p>有很多网站 将表情符号按类别进行收录，例如 <a target="_blank" rel="noopener" href="http://www.fhdq.net/emoji/emojifuhao.html">emoji符号大全</a></p>
<blockquote>
<p>常用</p>
</blockquote>
<p>🌹🍀🍎💰📱🌙🍁🍂🍃🌷💎🔪🔫🏀⚽⚡👄👍🔥</p>
<blockquote>
<p>表情</p>
</blockquote>
<p>😀😃😄😁😆😅🤣😂🙂🙃😉😊😇🥰😍🤩😘😗☺️😚😙🥲😋😛😜🤪😝🤑🤗🤭🤫🤔🤐🤨😐😑😶😏😒🙄😬🤥😌😔😪🤤😴😷🤒🤕🤢🤮🤧🥵🥶🥴😵🤯🤠🥳🥸😎🤓🧐😕😟🙁☹️😮😯😲😳🥺😦😧😨😰😥😢😭😱😖😣😞😓😩😫🥱😤😡😠🤬</p>
<blockquote>
<p>人物</p>
</blockquote>
<p>👶🧒👦👧🧑👱👨🧔👨‍🦰👨‍🦱👨‍🦳👨‍🦲👩👩‍🦰🧑‍🦰👩‍🦱🧑‍🦱👩‍🦳🧑‍🦳👩‍🦲🧑‍🦲👱‍♀️👱‍♂️🧓👴👵🙍🙍‍♂️🙍‍♀️🙎🙎‍♂️🙎‍♀️🙅🙅‍♂️🙅‍♀️🙆🙆‍♂️🙆‍♀️💁💁‍♂️💁‍♀️🙋🙋‍♂️🙋‍♀️🧏🧏‍♂️🧏‍♀️🙇🙇‍♂️🙇‍♀️🤦🤦‍♂️🤦‍♀️🤷🤷‍♂️🤷‍♀️🧑‍⚕️👨‍⚕️👩‍⚕️🧑‍🎓👨‍🎓👩‍🎓🧑‍🏫👨‍🏫👩‍🏫🧑‍⚖️👨‍⚖️👩‍⚖️🧑‍🌾👨‍🌾👩‍🌾🧑‍🍳👨‍🍳👩‍🍳🧑‍🔧👨‍🔧👩‍🔧🧑‍🏭👨‍🏭👩‍🏭🧑‍💼👨‍💼👩‍💼🧑‍🔬👨‍🔬👩‍🔬🧑‍💻👨‍💻👩‍💻🧑‍🎤👨‍🎤👩‍🎤🧑‍🎨👨‍🎨👩‍🎨🧑‍✈️👨‍✈️👩‍✈️🧑‍🚀👨‍🚀👩‍🚀🧑‍🚒👨‍🚒👩‍🚒👮👮‍♂️👮‍♀️🕵️🕵️‍♂️🕵️‍♀️💂💂‍♂️💂‍♀️🥷👷👷‍♂️👷‍♀️🤴👸👳👳‍♂️👳‍♀️👲🧕🤵🤵‍♂️🤵‍♀️👰👰‍♂️👰‍♀️🤰🤱👩‍🍼👨‍🍼🧑‍🍼👼🎅🤶🧑‍🎄🦸🦸‍♂️🦸‍♀️🦹🦹‍♂️🦹‍♀️🧙🧙‍♂️🧙‍♀️🧚🧚‍♂️🧚‍♀️🧛🧛‍♂️🧛‍♀️🧜🧜‍♂️🧜‍♀️🧝🧝‍♂️🧝‍♀️🧞🧞‍♂️🧞‍♀️🧟🧟‍♂️🧟‍♀️💆💆‍♂️💆‍♀️💇💇‍♂️💇‍♀️🚶🚶‍♂️🚶‍♀️🧍🧍‍♂️🧍‍♀️🧎🧎‍♂️🧎‍♀️🧑‍🦯👨‍🦯👩‍🦯🧑‍🦼👨‍🦼👩‍🦼🧑‍🦽👨‍🦽👩‍🦽🏃🏃‍♂️🏃‍♀️💃🕺🕴️👯👯‍♂️👯‍♀️🧖🧖‍♂️🧖‍♀️🧘🧑‍🤝‍🧑👭👫👬💏👩‍❤️‍💋‍👨👨‍❤️‍💋‍👨👩‍❤️‍💋‍👩💑👩‍❤️‍👨👨‍❤️‍👨👩‍❤️‍👩👪👨‍👩‍👦👨‍👩‍👧👨‍👩‍👧‍👦👨‍👩‍👦‍👦👨‍👩‍👧‍👧👨‍👨‍👦👨‍👨‍👧👨‍👨‍👧‍👦👨‍👨‍👦‍👦👨‍👨‍👧‍👧👩‍👩‍👦👩‍👩‍👧👩‍👩‍👧‍👦👩‍👩‍👦‍👦👩‍👩‍👧‍👧👨‍👦👨‍👦‍👦👨‍👧👨‍👧‍👦👨‍👧‍👧👩‍👦👩‍👦‍👦👩‍👧👩‍👧‍👦👩‍👧‍👧🗣️👤👥🫂</p>
<blockquote>
<p>手势</p>
</blockquote>
<p>👋🤚🖐️✋🖖👌🤌🤏✌️🤞🤟🤘🤙👈👉👆🖕👇☝️👍👎✊👊🤛🤜👏🙌👐🤲🤝🙏✍️💅🤳💪</p>
<blockquote>
<p>日常</p>
</blockquote>
<p>👣👀👁️👄💋👂🦻👃👅🧠🫀🫁🦷🦴💪🦾🦿🦵🦶👓🕶️🥽🥼🦺👔👕👖🧣🧤🧥🧦👗👘🥻🩱🩲🩳👙👚👛👜👝🎒🩴👞👟🥾🥿👠👡🩰👢👑👒🎩🎓🧢🪖⛑️💄💅💍💼🌂☂️💈🛀🛌💥💫💦💨</p>
<blockquote>
<p>其他网页推荐</p>
</blockquote>
<p><a target="_blank" rel="noopener" href="http://emojixd.com/">Emoji表情大全，颜文字百科</a></p>
<p><a target="_blank" rel="noopener" href="https://www.zfuhao.com/emoji">找符号网</a></p>
<p><a target="_blank" rel="noopener" href="https://bj.96weixin.com/emoji/">96编辑器</a></p>
 
      <!-- reward -->
      
    </div>
    

    <!-- copyright -->
    
    <footer class="article-footer">
       
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Markdown/" rel="tag">Markdown</a></li></ul>

    </footer>
  </div>

    
 
   
  
</article>

    
    <article
  id="post-JAVA分批处理数据简单示例"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2023/11/20/JAVA%E5%88%86%E6%89%B9%E5%A4%84%E7%90%86%E6%95%B0%E6%8D%AE%E7%AE%80%E5%8D%95%E7%A4%BA%E4%BE%8B/"
    >JAVA分批处理数据简单示例</a> 
</h2>
 

      
    </header>
     
    <div class="article-meta">
      <a href="/2023/11/20/JAVA%E5%88%86%E6%89%B9%E5%A4%84%E7%90%86%E6%95%B0%E6%8D%AE%E7%AE%80%E5%8D%95%E7%A4%BA%E4%BE%8B/" class="article-date">
  <time datetime="2023-11-20T05:17:24.000Z" itemprop="datePublished">2023-11-20</time>
</a> 
  <div class="article-category">
    <a class="article-category-link" href="/categories/%E5%A5%BD%E8%AE%B0%E6%80%A7%E4%B8%8D%E5%A6%82%E7%83%82%E7%AC%94%E5%A4%B4/">好记性不如烂笔头</a>
  </div>
   
    </div>
      
    <div class="article-entry" itemprop="articleBody">
       
  <h1 id="功能描述"><a href="#功能描述" class="headerlink" title="功能描述"></a>功能描述</h1><p>在处理业务时，经常遇到需要分批次处理数据的场景，例如有105条数据，每次推送20条，分批次推送</p>
<p>最后不足20条数据时，一次性推送全部剩余数据</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231120132006711-857445870.png" alt="image-20231120132006402"></p>
<h1 id="DEMO示例"><a href="#DEMO示例" class="headerlink" title="DEMO示例"></a>DEMO示例</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> shiguang.test;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.ArrayList;</span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BatchProcessingExample</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="comment">// 模拟接口返回的数据，这里用数字代表每一条数据</span></span><br><span class="line">        List&lt;Integer&gt; responseData = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">1</span>; i &lt;= <span class="number">105</span>; i++) &#123;</span><br><span class="line">            responseData.add(i);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="type">int</span> <span class="variable">batchSize</span> <span class="operator">=</span> <span class="number">20</span>; <span class="comment">// 每批次处理的数据量</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">// 计算需要多少批次来处理所有数据</span></span><br><span class="line">        <span class="type">int</span> <span class="variable">totalDataSize</span> <span class="operator">=</span> responseData.size();</span><br><span class="line">        <span class="type">int</span> <span class="variable">totalBatches</span> <span class="operator">=</span> (<span class="type">int</span>) Math.ceil((<span class="type">double</span>) totalDataSize / batchSize);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 分批次处理数据</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">batchNumber</span> <span class="operator">=</span> <span class="number">0</span>; batchNumber &lt; totalBatches; batchNumber++) &#123;</span><br><span class="line">            <span class="type">int</span> <span class="variable">startIndex</span> <span class="operator">=</span> batchNumber * batchSize;</span><br><span class="line">            <span class="type">int</span> <span class="variable">endIndex</span> <span class="operator">=</span> Math.min(startIndex + batchSize, totalDataSize);</span><br><span class="line"></span><br><span class="line">            List&lt;Integer&gt; batchData = responseData.subList(startIndex, endIndex);</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 在这里对批次数据进行处理，示例中只是打印数据</span></span><br><span class="line">            processBatchData(batchData);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 处理批次数据的方法，这里只是打印数据</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">processBatchData</span><span class="params">(List&lt;Integer&gt; batchData)</span> &#123;</span><br><span class="line">        <span class="keyword">for</span> (Integer data : batchData) &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;Processing data: &quot;</span> + data);</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(<span class="string">&quot;Batch processing complete.&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

 
      <!-- reward -->
      
    </div>
    

    <!-- copyright -->
    
    <footer class="article-footer">
       
    </footer>
  </div>

    
 
   
  
</article>

    
    <article
  id="post-遍历List移除元素时踩坑点"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2023/11/20/%E9%81%8D%E5%8E%86List%E7%A7%BB%E9%99%A4%E5%85%83%E7%B4%A0%E6%97%B6%E8%B8%A9%E5%9D%91%E7%82%B9/"
    >遍历List移除元素时踩坑点</a> 
</h2>
 

      
    </header>
     
    <div class="article-meta">
      <a href="/2023/11/20/%E9%81%8D%E5%8E%86List%E7%A7%BB%E9%99%A4%E5%85%83%E7%B4%A0%E6%97%B6%E8%B8%A9%E5%9D%91%E7%82%B9/" class="article-date">
  <time datetime="2023-11-20T04:37:02.000Z" itemprop="datePublished">2023-11-20</time>
</a> 
  <div class="article-category">
    <a class="article-category-link" href="/categories/%E8%B8%A9%E5%9D%91/">踩坑</a>
  </div>
   
    </div>
      
    <div class="article-entry" itemprop="articleBody">
       
  <h1 id="1、问题描述"><a href="#1、问题描述" class="headerlink" title="1、问题描述"></a>1、问题描述</h1><p>在遍历List并在循环体中移除元素时需要注意以下几点</p>
<ol>
<li><p>移除元素后数据总量会越来越小，可能造成数组下标越界</p>
</li>
<li><p>移除元素后，每个元素原有位置也会发生改变，需确认移除的元素是否是真正需要移除的</p>
</li>
<li><p>由于删除元素后，每个元素位置前移，会有部分数据直接跳过循环</p>
<p>例如 数组中有以下数据</p>
<table>
<thead>
<tr>
<th>i</th>
<th>0</th>
<th>1</th>
<th>2</th>
<th>3</th>
<th>4</th>
</tr>
</thead>
<tbody><tr>
<td>val</td>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>
</tbody></table>
<p>当 i &#x3D; 1 时 移除元素2，3会前移，下标1的值变为3，下标2的值变为4，后面的元素依次前移</p>
<p>当 i &#x3D; 1 的循环体结束后，i 自增，进入 i &#x3D; 2 的循环体，此时 i &#x3D; 2 对应的值为4 ，3被跳过，不经过循环体</p>
</li>
</ol>
<h1 id="2、问题复现"><a href="#2、问题复现" class="headerlink" title="2、问题复现"></a>2、问题复现</h1><p>假设我有一个数组，需要移除下标为 0，1，2，3 的元素</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231120125314494-287185037.png" alt="image-20231120125313864"></p>
<p>代码如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">testRemove1</span><span class="params">()</span>&#123;</span><br><span class="line">       List&lt;Integer&gt; numbers = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line">       <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; <span class="number">5</span>; i++) &#123;</span><br><span class="line">           numbers.add(i);</span><br><span class="line">       &#125;</span><br><span class="line">       System.out.println(<span class="string">&quot;old_numbers:&quot;</span>+numbers);</span><br><span class="line"></span><br><span class="line">       List&lt;Integer&gt; itemsToRemove = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line">       itemsToRemove.add(<span class="number">0</span>);</span><br><span class="line">       itemsToRemove.add(<span class="number">1</span>);</span><br><span class="line">       itemsToRemove.add(<span class="number">2</span>);</span><br><span class="line">       itemsToRemove.add(<span class="number">3</span>);</span><br><span class="line">       System.out.println(itemsToRemove);</span><br><span class="line"></span><br><span class="line">       <span class="comment">//移除元素时数据总长度减小,元素原本位置改变</span></span><br><span class="line">       <span class="comment">// 不仅会造成数组下标越界，移除的元素也并非想要移除的元素</span></span><br><span class="line">       <span class="keyword">for</span> (<span class="type">int</span>  integer : itemsToRemove) &#123;</span><br><span class="line">           numbers.remove(integer);</span><br><span class="line">       &#125;</span><br><span class="line"></span><br><span class="line">       System.out.println(<span class="string">&quot;new_numbers:&quot;</span>+numbers);</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure>

<p>假设我只需要移除下标为 0，1 的元素，下标0 对应的值应为0，下标1 对应的值应为1</p>
<p>移除后的元素应该是 [2，3，4] 但结果却是 [1，3，4]</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231120125731060-518159466.png" alt="image-20231120125730760"></p>
<h1 id="3、解决方案"><a href="#3、解决方案" class="headerlink" title="3、解决方案"></a>3、解决方案</h1><p>可以使用 <code>ListIterator</code> 来安全地在迭代过程中删除元素，而不影响后续元素的位置</p>
<p><code>ListIterator</code> 是 Java 中 <code>List</code> 接口提供的一个迭代器，相比普通的迭代器，它具有双向遍历的能力，允许在迭代过程中插入、删除元素，以及获取当前位置的索引。这使得在使用 <code>List</code> 类型的集合时，特别是在需要在迭代过程中修改集合的情况下，<code>ListIterator</code> 是一个更加强大的工具。</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231120130456248-1856484750.png" alt="image-20231120130455982"></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">testRemove2</span><span class="params">()</span>&#123;</span><br><span class="line">        List&lt;Integer&gt; numbers = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; <span class="number">5</span>; i++) &#123;</span><br><span class="line">            numbers.add(i);</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(<span class="string">&quot;old_numbers:&quot;</span>+numbers);</span><br><span class="line"></span><br><span class="line">        List&lt;Integer&gt; itemsToRemove = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line">        itemsToRemove.add(<span class="number">0</span>);</span><br><span class="line">        itemsToRemove.add(<span class="number">1</span>);</span><br><span class="line">        itemsToRemove.add(<span class="number">2</span>);</span><br><span class="line">        itemsToRemove.add(<span class="number">3</span>);</span><br><span class="line">        System.out.println(itemsToRemove);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 使用 ListIterator 正序遍历并删除需要删除的元素</span></span><br><span class="line">        ListIterator&lt;Integer&gt; iterator = numbers.listIterator();</span><br><span class="line">        <span class="keyword">while</span> (iterator.hasNext()) &#123;</span><br><span class="line">            <span class="type">int</span> <span class="variable">indexToRemove</span> <span class="operator">=</span> iterator.nextIndex();</span><br><span class="line">            <span class="type">Integer</span> <span class="variable">nextVal</span> <span class="operator">=</span> iterator.next();<span class="comment">// 移动到下一个位置</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//            System.out.println(&quot;index:&quot;+indexToRemove+&quot;,value:&quot;+nextVal);</span></span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (itemsToRemove.contains(nextVal))&#123;</span><br><span class="line">                iterator.remove(); <span class="comment">// 安全地移除当前元素</span></span><br><span class="line">                System.out.println(<span class="string">&quot;移除元素 index:&quot;</span>+indexToRemove+<span class="string">&quot;,value:&quot;</span>+nextVal);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;new_numbers:&quot;</span>+numbers);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<p>如果需要根据下标移除元素可以逆序遍历，此时<code>itemsToRemove.contains(indexToRemove)</code>使用的是下标</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231120134702755-245472491.png" alt="image-20231120134702313"></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">testRemove3</span><span class="params">()</span>&#123;</span><br><span class="line">        List&lt;Integer&gt; numbers = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; <span class="number">5</span>; i++) &#123;</span><br><span class="line">            numbers.add(i);</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(<span class="string">&quot;old_numbers:&quot;</span>+numbers);</span><br><span class="line"></span><br><span class="line">        List&lt;Integer&gt; itemsToRemove = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line">        itemsToRemove.add(<span class="number">0</span>);</span><br><span class="line">        itemsToRemove.add(<span class="number">1</span>);</span><br><span class="line">        itemsToRemove.add(<span class="number">2</span>);</span><br><span class="line">        itemsToRemove.add(<span class="number">3</span>);</span><br><span class="line">        System.out.println(itemsToRemove);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        <span class="comment">// 使用 ListIterator 逆序遍历并删除需要删除的元素</span></span><br><span class="line">        ListIterator&lt;Integer&gt; iterator = numbers.listIterator(numbers.size());</span><br><span class="line">        <span class="keyword">while</span> (iterator.hasPrevious()) &#123;</span><br><span class="line">            <span class="type">int</span> <span class="variable">indexToRemove</span> <span class="operator">=</span> iterator.previousIndex();</span><br><span class="line">            <span class="type">Integer</span> <span class="variable">previousVal</span> <span class="operator">=</span> iterator.previous();<span class="comment">// 移动到上一个位置</span></span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (itemsToRemove.contains(indexToRemove))&#123;</span><br><span class="line">                iterator.remove(); <span class="comment">// 安全地移除当前元素</span></span><br><span class="line">                System.out.println(<span class="string">&quot;移除元素 index:&quot;</span>+indexToRemove+<span class="string">&quot;,value:&quot;</span>+previousVal);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;new_numbers:&quot;</span>+numbers);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<p>根据下标移除元素时正序遍历可能会出问题</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231120140148055-1669205910.png" alt="image-20231120140147752"></p>
<h2 id="ListIterator常见方法"><a href="#ListIterator常见方法" class="headerlink" title="ListIterator常见方法"></a>ListIterator常见方法</h2><ul>
<li><code>hasNext()</code>：判断是否还有下一个元素。</li>
<li><code>hasPrevious()</code>：判断是否还有上一个元素。</li>
<li><code>next()</code>：返回下一个元素。</li>
<li><code>previous()</code>：返回上一个元素。</li>
<li><code>nextIndex()</code>：返回下一个元素的索引。</li>
<li><code>previousIndex()</code>：返回上一个元素的索引。</li>
<li><code>add(E element)</code>：在当前位置插入指定的元素。</li>
<li><code>set(E element)</code>：用指定的元素替换上一次调用 <code>next()</code> 或 <code>previous()</code> 返回的元素。</li>
<li><code>remove()</code>：移除上一次调用 <code>next()</code> 或 <code>previous()</code> 返回的元素。</li>
</ul>
<h2 id="ListIterator-两种初始化方式"><a href="#ListIterator-两种初始化方式" class="headerlink" title="ListIterator 两种初始化方式"></a>ListIterator 两种初始化方式</h2><p><code>ListIterator</code> 有两个不同的初始化方式，分别是：</p>
<ol>
<li><code>ListIterator&lt;Integer&gt; iterator = numbers.listIterator()</code>：通过这种方式初始化的 <code>ListIterator</code> 位于列表的开始位置，即索引为 0 的位置。当你使用 <code>iterator.next()</code> 时，它会返回列表的第一个元素。</li>
<li><code>ListIterator&lt;Integer&gt; iterator = numbers.listIterator(numbers.size())</code>：通过这种方式初始化的 <code>ListIterator</code> 位于列表的末尾位置，即索引为 <code>list.size()</code> 的位置。当你使用 <code>iterator.previous()</code> 时，它会返回列表的最后一个元素。</li>
</ol>
<p>总的来说，这两种方式初始化的 <code>ListIterator</code> 分别定位在列表的开始和末尾位置，选择取决于你是希望从前向后遍历还是从后向前遍历。</p>
<p>示例：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">javaCopy codeList&lt;String&gt; myList = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;(Arrays.asList(<span class="string">&quot;A&quot;</span>, <span class="string">&quot;B&quot;</span>, <span class="string">&quot;C&quot;</span>, <span class="string">&quot;D&quot;</span>));</span><br><span class="line"></span><br><span class="line"><span class="comment">// 从前向后遍历</span></span><br><span class="line">ListIterator&lt;String&gt; iteratorForward = myList.listIterator();</span><br><span class="line"><span class="keyword">while</span> (iteratorForward.hasNext()) &#123;</span><br><span class="line">    System.out.print(iteratorForward.next() + <span class="string">&quot; &quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 输出: A B C D</span></span><br><span class="line"></span><br><span class="line">System.out.println();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 从后向前遍历</span></span><br><span class="line">ListIterator&lt;String&gt; iteratorBackward = myList.listIterator(myList.size());</span><br><span class="line"><span class="keyword">while</span> (iteratorBackward.hasPrevious()) &#123;</span><br><span class="line">    System.out.print(iteratorBackward.previous() + <span class="string">&quot; &quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 输出: D C B A</span></span><br></pre></td></tr></table></figure>

<p>在这个示例中，<code>iteratorForward</code> 从前向后遍历列表，而 <code>iteratorBackward</code> 从后向前遍历列表。</p>
 
      <!-- reward -->
      
    </div>
    

    <!-- copyright -->
    
    <footer class="article-footer">
       
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/List/" rel="tag">List</a></li></ul>

    </footer>
  </div>

    
 
   
  
</article>

    
    <article
  id="post-Git因文件过大导致提交失败解决方案"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2023/11/16/Git%E5%9B%A0%E6%96%87%E4%BB%B6%E8%BF%87%E5%A4%A7%E5%AF%BC%E8%87%B4%E6%8F%90%E4%BA%A4%E5%A4%B1%E8%B4%A5%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/"
    >Git因文件过大导致提交失败解决方案</a> 
</h2>
 

      
    </header>
     
    <div class="article-meta">
      <a href="/2023/11/16/Git%E5%9B%A0%E6%96%87%E4%BB%B6%E8%BF%87%E5%A4%A7%E5%AF%BC%E8%87%B4%E6%8F%90%E4%BA%A4%E5%A4%B1%E8%B4%A5%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/" class="article-date">
  <time datetime="2023-11-15T16:04:01.000Z" itemprop="datePublished">2023-11-16</time>
</a> 
  <div class="article-category">
    <a class="article-category-link" href="/categories/%E8%B8%A9%E5%9D%91/">踩坑</a>
  </div>
   
    </div>
      
    <div class="article-entry" itemprop="articleBody">
       
  <h2 id="问题描述"><a href="#问题描述" class="headerlink" title="问题描述"></a>问题描述</h2><p>git推送到远程时因个别文件过大导致推送失败</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231116000643175-1811993802.png" alt="image-20231116000642638"></p>
<p>Gitee托管平台对不同套餐的用户采用了不同的配额限制，详情可查阅<a target="_blank" rel="noopener" href="https://help.gitee.com/repository/base/%E4%BB%93%E5%BA%93%E4%BD%93%E7%A7%AF%E8%BF%87%E5%A4%A7%EF%BC%8C%E5%A6%82%E4%BD%95%E5%87%8F%E5%B0%8F#%E6%A6%82%E8%BF%B0">Gitee产品文档</a></p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231116001113757-1612266466.png" alt="image-20231116001113295"></p>
<h2 id="解决方法"><a href="#解决方法" class="headerlink" title="解决方法"></a>解决方法</h2><h3 id="1、查看超出限额的大文件"><a href="#1、查看超出限额的大文件" class="headerlink" title="1、查看超出限额的大文件"></a>1、查看超出限额的大文件</h3><p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231116001707414-1980373033.png" alt="image-20231116001706912"></p>
<p>命令如下，其中<code>557b10ce603309c9a25c0e3924ce3d681104f18c</code> 为错误信息中给出的文件的哈希值</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git rev-list --objects --all | grep 557b10ce603309c9a25c0e3924ce3d681104f18c</span><br></pre></td></tr></table></figure>

<h3 id="2、查看提交记录"><a href="#2、查看提交记录" class="headerlink" title="2、查看提交记录"></a>2、查看提交记录</h3><p>使用 <code>git log</code> 命令可查看历史提交信息，会显示提交记录的<strong>Commit Hash</strong>，作者信息、提交时间、提交说明等信息， 每个提交都有一个唯一的 SHA-1 校验和，用于标识该提交</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231116003453057-860135841.png" alt="image-20231116003452483"></p>
<h3 id="3、撤销commit记录"><a href="#3、撤销commit记录" class="headerlink" title="3、撤销commit记录"></a>3、撤销commit记录</h3><p>依次撤销已经commit但未push到远程的提交记录</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231116003406595-775683083.png" alt="image-20231116003405991"></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git reset Commit &lt;HashCommit Hash&gt;</span><br></pre></td></tr></table></figure>

<h3 id="4、删除本地大文件"><a href="#4、删除本地大文件" class="headerlink" title="4、删除本地大文件"></a>4、删除本地大文件</h3><h3 id="5、重新提交并推送"><a href="#5、重新提交并推送" class="headerlink" title="5、重新提交并推送"></a>5、重新提交并推送</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">git add .</span><br><span class="line">git commit -m &#x27;提交说明&#x27;</span><br><span class="line">git push</span><br></pre></td></tr></table></figure>

<p>最终完美解决</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231116004231720-102402302.png" alt="image-20231116004231196"></p>
<p>参考文章</p>
<p><a target="_blank" rel="noopener" href="https://cloud.tencent.com/developer/article/1466149">Git push大文件失败解决</a></p>
 
      <!-- reward -->
      
    </div>
    

    <!-- copyright -->
    
    <footer class="article-footer">
       
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/git/" rel="tag">git</a></li></ul>

    </footer>
  </div>

    
 
   
  
</article>

    
    <article
  id="post-E9安装手册"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2023/11/14/E9%E5%AE%89%E8%A3%85%E6%89%8B%E5%86%8C/"
    >E9安装手册</a> 
</h2>
 

      
    </header>
     
    <div class="article-meta">
      <a href="/2023/11/14/E9%E5%AE%89%E8%A3%85%E6%89%8B%E5%86%8C/" class="article-date">
  <time datetime="2023-11-14T10:22:37.612Z" itemprop="datePublished">2023-11-14</time>
</a> 
  <div class="article-category">
    <a class="article-category-link" href="/categories/%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B/">安装教程</a>
  </div>
   
    </div>
      
    <div class="article-entry" itemprop="articleBody">
       
  <h1 id="E9安装手册"><a href="#E9安装手册" class="headerlink" title="E9安装手册"></a>E9安装手册</h1><h2 id="安装包获取"><a href="#安装包获取" class="headerlink" title="安装包获取"></a>安装包获取</h2><p>安装所需文件可在泛微emobile技术门户获取，泛微会定期维护</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114224500581-1299887758.png" alt="image-20231114224459866"></p>
<h2 id="自动部署"><a href="#自动部署" class="headerlink" title="自动部署"></a>自动部署</h2><h3 id="1、通过-SSH-工具连接上-linux，创建应用程序目录"><a href="#1、通过-SSH-工具连接上-linux，创建应用程序目录" class="headerlink" title="1、通过 SSH 工具连接上 linux，创建应用程序目录"></a>1、通过 SSH 工具连接上 linux，创建应用程序目录</h3><p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114182415612-2082326022.png" alt="image-20231114182416386"></p>
<p>可根据客户实际要求创建在任何路径下，保证有足够的空间即可，相关命令为：</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> -p /usr/weaver</span><br></pre></td></tr></table></figure>

<h3 id="2、通过-FTP-工具上传程序"><a href="#2、通过-FTP-工具上传程序" class="headerlink" title="2、通过 FTP 工具上传程序"></a>2、通过 FTP 工具上传程序</h3><p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114183225920-1661277848.png" alt="image-20231114183226839"></p>
<p>将本地的 ECOLOGY相关程序上传到创建好的 weaver 目录下。共四个，JDK，RESIN，ECOLOGY 和 Ecology_setup_forLinux_*.py 文件。<strong>（JDK 必须提前下载好）</strong></p>
<h3 id="3、执行-Ecology-setup-forLinux-py"><a href="#3、执行-Ecology-setup-forLinux-py" class="headerlink" title="3、执行 Ecology_setup_forLinux_*.py"></a>3、执行 Ecology_setup_forLinux_*.py</h3><p>即输入命令：python Ecology_setup_forLinux_*.py 回车，此处我使用的版本为v2.66</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python Ecology_setup_forLinux_v2<span class="number">.66</span>.py</span><br></pre></td></tr></table></figure>

<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114183453528-1838303529.png" alt="image-20231114183454149"></p>
<p>如果选择 1 自动执行以下三步操作： </p>
<p>第一步：解压缩。（Linux 必须支持 unzip 及 tar 命令，没有需要提前安装好，否则无法解压） </p>
<p>第二步：给 ecology、jdk、resin 三个目录赋权。 </p>
<p>第三步：修改配置文件。设置路径、内存、端口。（内存和端口可在安装过程中进行调整）。 </p>
<p>如果选择 2 自动解压缩失败可在手动解压好的情况下，进行第二步和第三步配置。 </p>
<p>如果选择 3 查看配置好的相关参数，仅查看，若要调整，可再选择 2 或手动调整。</p>
<p>此处输入1</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114184102932-842439474.png" alt="image-20231114184103511"></p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114184352271-147344098.png" alt="image-20231114184352829"></p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114184505473-1544093421.png" alt="image-20231114184506165"></p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114193416303-1152725752.png" alt="image-20231114193414751"></p>
<p>本页面为配置完成后，切换到 Resin4&#x2F;bin (或者Resin&#x2F;bin) 目录后，启动 resin 服务。</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">cd /usr/weaver/Resin4/bin</span><br><span class="line">./startresin.sh</span><br></pre></td></tr></table></figure>

<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114193716924-2136306748.png" alt="image-20231114193711901"></p>
<p>服务启动好后，访问服务器ip及刚才设置的端口即可进入数据库初始化页面</p>
<p>能打开此页面代表Resin服务部署成功</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114221800304-1317730758.png" alt="image-20231114221759787"></p>
<p>如果 自动部署操作不成功，那就只能手动部署。 </p>
<h2 id="手动部署"><a href="#手动部署" class="headerlink" title="手动部署"></a>手动部署</h2><h3 id="（1）端口（三个端口）"><a href="#（1）端口（三个端口）" class="headerlink" title="（1）端口（三个端口）"></a>（1）端口（三个端口）</h3><p>http 端口（Resin&#x2F;conf&#x2F;resin.properties）浏览器访问时用到的端口，根据实际调整 </p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">app.http : 80</span><br></pre></td></tr></table></figure>

<p>server 端口（Resin&#x2F;conf&#x2F;resin.properties）默认不需要修改 </p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">app_servers : 127.0.0.1:6800</span><br></pre></td></tr></table></figure>

<p>watchdog 端口（Resin&#x2F;conf&#x2F;resin.xml）默认不需要修改 </p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">server-multi</span> <span class="attr">id-prefix</span>=<span class="string">&quot;app-&quot;</span> <span class="attr">address-list</span>=<span class="string">&quot;$&#123;app_servers&#125;&quot;</span> <span class="attr">port</span>=<span class="string">&quot;6800&quot;</span>&gt;</span></span><br><span class="line">	    <span class="tag">&lt;<span class="name">watchdog-port</span>&gt;</span>6600<span class="tag">&lt;/<span class="name">watchdog-port</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">server-multi</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h3 id="（2）内存（Resin-x2F-conf-x2F-resin-properties）"><a href="#（2）内存（Resin-x2F-conf-x2F-resin-properties）" class="headerlink" title="（2）内存（Resin&#x2F;conf&#x2F;resin.properties）"></a>（2）内存（Resin&#x2F;conf&#x2F;resin.properties）</h3><p>根据实际可用内存调整，不要低于 3550</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"># Arg passed directly to the JVM</span><br><span class="line"> jvm_args  : -Xmx5550m -Xms5550m -XX:CompileThreshold=100000 -XX:ReservedCodeCacheSize=512m -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:-OmitStackTraceInFastThrow -XX:+UseParNewGC -XX:+DisableExplicitGC -javaagent:wagent.jar -javaagent:stophotdeploy.jar -Djdk.tls.ephemeralDHKeySize=2048 -Dfile.encoding=GBK -javaagent:rasp/rasp.jar</span><br></pre></td></tr></table></figure>

<h3 id="（3）路径（两个路径）"><a href="#（3）路径（两个路径）" class="headerlink" title="（3）路径（两个路径）"></a>（3）路径（两个路径）</h3><p>JDK 路径（Resin&#x2F;conf&#x2F;resin.xml）根据实际调整</p>
<p>官方部署文档：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&lt;!--</span><br><span class="line"> - You can change the compiler to &quot;javac&quot;, &quot;eclipse&quot; or &quot;internal&quot;.</span><br><span class="line"> --&gt;</span><br><span class="line"> &lt;javac compiler=&quot;/usr/weaver/jdk1.8.0_151/bin/javac&quot; args=&quot;-encoding UTF-8&quot;/&gt;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>我本地实际为：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&lt;!--</span><br><span class="line">     - You can change the compiler to &quot;javac&quot;, &quot;eclipse&quot; or &quot;internal&quot;.</span><br><span class="line">    --&gt;</span><br><span class="line">   &lt;javac compiler=&quot;internal&quot; args=&quot;-encoding UTF-8&quot;/&gt;</span><br></pre></td></tr></table></figure>



<p>应用程序路径（Resin&#x2F;conf&#x2F;resin.xml）根据实际调整</p>
<p><code>&lt;web-app id=&quot;/&quot; root-directory=&quot;/usr/weaver/ecology&quot;&gt;</code></p>
<p>官方部署文档：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- the default host, matching any host name --&gt;</span><br><span class="line"> &lt;host id=&quot;&quot; root-directory=&quot;.&quot;&gt;</span><br><span class="line"> &lt;!--</span><br><span class="line"> - webapps can be overridden/extended in the resin.xml</span><br><span class="line"> --&gt;</span><br><span class="line"> &lt;web-app id=&quot;/&quot; root-directory=&quot;/usr/weaver/ecology&quot;&gt;</span><br><span class="line">&lt;servlet-mapping url-pattern=&#x27;/weaver/*&#x27; servlet-name=&#x27;invoker&#x27;/&gt;</span><br><span class="line"> &lt;/web-app&gt;</span><br><span class="line"> &lt;/host&gt;</span><br></pre></td></tr></table></figure>

<p>我本地实际为：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">&lt;host id=&quot;&quot; root-directory=&quot;.&quot;&gt;</span><br><span class="line"></span><br><span class="line">   &lt;access-log path=&quot;logs/access.log&quot; archive-format=&quot;access-%Y%m%d.log.gz&quot; format=&#x27;%s` %&#123;loginidweaver&#125;c` %D` %h` %n` %u` &quot;%t&quot;` &quot;%r&quot;`  &quot;%&#123;Referer&#125;i&quot;&#x27; rollover-period=&quot;1D&quot;&gt;</span><br><span class="line">	   &lt;exclude&gt;\.gif$&lt;/exclude&gt;</span><br><span class="line">	   &lt;exclude&gt;\.jpg$&lt;/exclude&gt;</span><br><span class="line">	   &lt;exclude&gt;\.png$&lt;/exclude&gt;</span><br><span class="line">	   &lt;exclude&gt;\.js$&lt;/exclude&gt;</span><br><span class="line">	   &lt;exclude&gt;\.css$&lt;/exclude&gt;</span><br><span class="line">	   &lt;exclude&gt;\.html$&lt;/exclude&gt;</span><br><span class="line">	   &lt;exclude&gt;\.htm$&lt;/exclude&gt;</span><br><span class="line">	   &lt;exclude&gt;\.swf$&lt;/exclude&gt;</span><br><span class="line">	   &lt;exclude&gt;\.cur$&lt;/exclude&gt;</span><br><span class="line">	&lt;/access-log&gt;</span><br><span class="line"></span><br><span class="line">	&lt;stdout-log path=&quot;log/stdout.log&quot; archive-format=&quot;stdout-%Y%m%d.log.gz&quot; timestamp=&quot;[%Y.%m.%d %H:%M:%S.%s]&quot; rollover-period=&quot;1D&quot;/&gt;</span><br><span class="line">	&lt;stderr-log path=&quot;log/stderr.log&quot; archive-format=&quot;stderr-%Y%m%d.log.gz&quot; timestamp=&quot;[%Y.%m.%d %H:%M:%S.%s]&quot; rollover-period=&quot;1D&quot;/&gt;</span><br><span class="line"></span><br><span class="line">      &lt;!--</span><br><span class="line">         - webapps can be overridden/extended in the resin.xml</span><br><span class="line">        --&gt;</span><br><span class="line">      &lt;web-app id=&quot;/&quot; root-directory=&quot;/usr/weaver/ecology&quot;&gt;</span><br><span class="line">			&lt;servlet-mapping url-pattern=&#x27;/weaver/*&#x27; servlet-name=&#x27;invoker&#x27;/&gt;</span><br><span class="line">			&lt;form-parameter-max&gt;100000&lt;/form-parameter-max&gt;</span><br><span class="line">      &lt;/web-app&gt;</span><br><span class="line"></span><br><span class="line">    &lt;/host&gt;</span><br></pre></td></tr></table></figure>

<h3 id="（4）-服务（三个文件）"><a href="#（4）-服务（三个文件）" class="headerlink" title="（4） 服务（三个文件）"></a>（4） 服务（三个文件）</h3><p>resin.sh(Resin4&#x2F;bin&#x2F;resin.sh)根据实际设置 JDK 路径 </p>
<p>JAVA_HOME&#x3D;<font color = red><strong>&#x2F;usr&#x2F;weaver&#x2F;jdk1.8.0_151</strong></font></p>
<p>startresin.sh(Resin4&#x2F;bin&#x2F;startresin.sh)根据实际设置 resin.sh 路径 </p>
<p>ulimit -n 65535 </p>
<p>export LC_ALL&#x3D;zh_CN.gbk </p>
<p>export LANG&#x3D;zh_CN.gbk</p>
<p> <font color = red>&#x2F;usr&#x2F;weaver&#x2F;Resin4&#x2F;bin&#x2F;resin.sh</font>&gt; start </p>
<p><strong>stopresin.sh</strong>(Resin4&#x2F;bin&#x2F;stopresin.sh) 根据实际设置 resin.sh 路径 </p>
<p><font color = red>&#x2F;usr&#x2F;weaver&#x2F;Resin4&#x2F;bin&#x2F;resin.sh</font> stop</p>
<h3 id="（5）-检查字符集"><a href="#（5）-检查字符集" class="headerlink" title="（5） 检查字符集"></a>（5） 检查字符集</h3><p><font color=red>不建议修改，修改后Linux环境会乱码，可跳过</font></p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231115214450615-1786737702.png" alt="image-20231115214449680"></p>
<p>检查当前系统是不是使用 zh_CN.gbk </p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">env | grep LANG</span><br></pre></td></tr></table></figure>

<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114214458667-1551846510.png" alt="image-20231114214453735"></p>
<p>若不是 zh_CN.gbk 字符集，则通过 <code>export LANG=zh_CN.gbk</code> 命令来指定</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114214607453-1678677455.png" alt="image-20231114214606820"></p>
<p>这种方式在重启系统后将失效，若要一直有效，可编辑<code>/etc/profile</code> 文件</p>
<p>在最后添加 <code>export LANG=zh_CN.gbk</code></p>
<h3 id="（6）对目录赋予权限"><a href="#（6）对目录赋予权限" class="headerlink" title="（6）对目录赋予权限"></a>（6）对目录赋予权限</h3><p>对Resin 和 jdk 目录使用 <code>chmod +x </code>赋予可执行权限</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114215811531-645230160.png" alt="image-20231114215810827"></p>
<p>命令如下</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">cd /usr/weaver/</span><br><span class="line">chmod +x Resin4/*</span><br><span class="line">chmod +x jdk1.8.0_151/*</span><br></pre></td></tr></table></figure>

<h3 id="（7）检查文件格式"><a href="#（7）检查文件格式" class="headerlink" title="（7）检查文件格式"></a>（7）检查文件格式</h3><p>（在 windows 下编写的脚本文件，放到 Linux 中无法识别）</p>
<p>切换到Resin的bin目录，使用 <code>vi</code>命令查看shell脚本内容 </p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">cd /usr/weaver/Resin4/bin</span><br><span class="line">vi startresin.sh </span><br></pre></td></tr></table></figure>



<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114220051926-1511995118.png" alt="image-20231114220051405"></p>
<p>显示内容如下</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114220549524-1712176701.png" alt="image-20231114220548940"></p>
<p>如果是这个结果，则代表文件格式是正确的，直接输入<code>:q!</code> (冒号+q+感叹号表示不保存修) 改直接退出 vi 操作</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114220638753-1823912521.png" alt="image-20231114220638213"></p>
<p>如果是这个结果，则代表文件格式是错误的，需要转换格式，否则无法启动</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114220713509-403661258.png" alt="image-20231114220713062"></p>
<p>输入<code>:set ff=unix</code> (冒号+set+空格+ff 等于 unix 表示把文件格式由 dos 转换为 unix)</p>
<p> 回车后再输入<code>:wq</code> (冒号+w+q 表示保存之前的修改并退出 vi 操作)</p>
<p> 除了 startresin.sh 外，resin.sh 和 stopresin.sh 也必须检查，保证文件格式正确</p>
<h2 id="初始化数据库"><a href="#初始化数据库" class="headerlink" title="初始化数据库"></a>初始化数据库</h2><h3 id="修改验证码"><a href="#修改验证码" class="headerlink" title="修改验证码"></a>修改验证码</h3><p>为方便记忆及日后license维护，可以修改验证码默认值为1</p>
<p>验证码默认值为<code>wEAver2018</code>可在文件 <code>ecology\WEB-INF\code.key</code> 中查看</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114222545494-920588789.png" alt="image-20231114222537960"></p>
<p>可直接修改<code>code.key</code> 文件，也可通过初始化页面修改</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114222716045-1613342454.png" alt="image-20231114222715608"></p>
<h3 id="创建数据库"><a href="#创建数据库" class="headerlink" title="创建数据库"></a>创建数据库</h3><p>因为无论是否使用现有数据库，数据库均需手动到数据库中创建，程序无法自动生成</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114223330170-2022909818.png" alt="image-20231114223322650"></p>
<p>手动创建数据库</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114223233386-79675942.png" alt="image-20231114223232833"></p>
<p>创建好后即可开始初始化数据库，初始化耗时较长，需耐心等待</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114223529763-1002787339.png" alt="image-20231114223529239"></p>
<p>若想重新初始化数据库将<code>ecology\WEB-INF\prop\weaver.properties</code>文件内容清空</p>
<p>重启服务后重新访问OA地址即可重新进入初始化界面</p>
<p>当然，也可直接修改数据库连接地址，数据库名，用户名，密码等配置信息</p>
<p>数据库初始化完成之后重新登录系统即可,管理员初始密码为 <code>Weaver@2001</code>,可通过sql改为1</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">-- 将用户登录密码改为1   默认密码 Weaver@2001</span></span><br><span class="line"><span class="keyword">update</span> hrmresource <span class="keyword">set</span> password<span class="operator">=</span><span class="string">&#x27;C4CA4238A0B923820DCC509A6F75849B&#x27;</span> </span><br><span class="line"><span class="comment">-- 系统管理员登录密码改为1</span></span><br><span class="line"><span class="keyword">update</span> hrmresourcemanager <span class="keyword">set</span> password<span class="operator">=</span><span class="string">&#x27;C4CA4238A0B923820DCC509A6F75849B&#x27;</span> </span><br></pre></td></tr></table></figure>



<p>首次登录需要提交license授权文件，授权后会进入Ecology升级确认页面，按操作指引操作即可</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231115125011991-1623633147.png" alt="image-20231115125011884"></p>
<h2 id="启用非标功能"><a href="#启用非标功能" class="headerlink" title="启用非标功能"></a>启用非标功能</h2><h3 id="申请非标包"><a href="#申请非标包" class="headerlink" title="申请非标包"></a>申请非标包</h3><p>可通过<code>Ecology功能及版本升级申请流程</code> 申请本地DEMO非标包</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231115131356664-529486860.png" alt="image-20231115131356893"></p>
<p>申请时需注意以下信息</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231115131226869-1922554369.png" alt="image-20231115131226722"></p>
<h3 id="升级非标"><a href="#升级非标" class="headerlink" title="升级非标"></a>升级非标</h3><p>将非标包解压后直接覆盖到ecology目录，重启Resin服务</p>
<p>重启后重新访问OA进入升级页面</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231115220236614-1231633897.png" alt="image-20231115220235973"></p>
<p>使用系统管理员账号登录，进行升级操作</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231115220326442-1582505146.png" alt="image-20231115220325965"></p>
<p>填写数据库地址后六位信息及数据库名后三位</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231115220737085-1842553394.png" alt="image-20231115220736382"></p>
<p>详细信息可在 <code>ecology/WEB-INF/prop/weaver.properties</code> 中查看</p>
<p>以我本地服务为例，数据库地址为 127.0.0.1，后六位为 .0.0.1；数据库名为ecology,后三位为ogy</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231115221002253-1830263147.png" alt="image-20231115221001654"></p>
<p>重要提醒确认</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231115221154375-881579704.png" alt="image-20231115221153868"></p>
<p>确认其他配置</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231115221214671-1405785337.png" alt="image-20231115221214071"></p>
<p>点击确定后开始执行sql脚本</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231115221319940-1568502724.png" alt="image-20231115221319203"></p>
<p>脚本执行完毕后重新登录OA进入<strong>Ecology升级完成确认页面</strong>，按照操作指引一次点击下一步即可</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231115223622481-1394942944.png" alt="image-20231115223621537"></p>
<h3 id="启用非标"><a href="#启用非标" class="headerlink" title="启用非标"></a>启用非标</h3><p>使用系统管理员登录OA后右上角设置按钮点击授权信息</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231115223817514-1164129625.png" alt="image-20231115223816956"></p>
<p>此时非标功能启用情况已启用数量为0</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231115223907249-868811263.png" alt="image-20231115223906464"></p>
<p>点击蓝色链接进入非标功能管理界面，勾选需要启用的非标进行启用</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231115224035412-509391539.png" alt="image-20231115224034684"></p>
<p>启用时会有相应提醒</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231115224133592-5872113.png" alt="image-20231115224132848"></p>
<p>启用后可重新查看已启用数量确认</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231115224239180-1488921123.png" alt="image-20231115224238550"></p>
 
      <!-- reward -->
      
    </div>
    

    <!-- copyright -->
    
    <footer class="article-footer">
       
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Ecology/" rel="tag">Ecology</a></li></ul>

    </footer>
  </div>

    
 
   
  
</article>

    
    <article
  id="post-定制化代码生成项目-day2"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2023/11/14/%E5%AE%9A%E5%88%B6%E5%8C%96%E4%BB%A3%E7%A0%81%E7%94%9F%E6%88%90%E9%A1%B9%E7%9B%AE-day2/"
    >定制化代码生成项目_day2</a> 
</h2>
 

      
    </header>
     
    <div class="article-meta">
      <a href="/2023/11/14/%E5%AE%9A%E5%88%B6%E5%8C%96%E4%BB%A3%E7%A0%81%E7%94%9F%E6%88%90%E9%A1%B9%E7%9B%AE-day2/" class="article-date">
  <time datetime="2023-11-14T04:59:20.000Z" itemprop="datePublished">2023-11-14</time>
</a> 
  <div class="article-category">
    <a class="article-category-link" href="/categories/%E9%A1%B9%E7%9B%AE%E7%AC%94%E8%AE%B0/">项目笔记</a>
  </div>
   
    </div>
      
    <div class="article-entry" itemprop="articleBody">
       
  <h2 id="前情回顾"><a href="#前情回顾" class="headerlink" title="前情回顾"></a>前情回顾</h2><p>在上一期教程中，我们已经了解了整个定制化代码生成项目的需求背景、三大阶段、技术选型，并且通过对三个阶段分别进行分析，学习了各阶段的业务流程、实现思路和待解决的问题。</p>
<p>从本节教程开始，鱼皮会依次带大家完成三个阶段的开发实现，解决之前提到的各种问题。</p>
<h2 id="本节重点"><a href="#本节重点" class="headerlink" title="本节重点"></a>本节重点</h2><p>本节教程属于项目的第一阶段 —— 开发本地代码生成器。</p>
<p>重点内容：</p>
<ol>
<li>完成项目的初始化</li>
<li>静态文件生成</li>
<li>动态文件代码生成</li>
<li>FreeMarker 模板引擎入门及实战</li>
<li>动静结合 - ACM 示例项目模板代码生成</li>
</ol>
<h2 id="一、项目初始化"><a href="#一、项目初始化" class="headerlink" title="一、项目初始化"></a>一、项目初始化</h2><h3 id="1、初始化根目录"><a href="#1、初始化根目录" class="headerlink" title="1、初始化根目录"></a>1、初始化根目录</h3><p>由于我们的项目包含多个阶段，本质上是多个项目，所以为了统一管理整个项目，我们创建一个干净的<code> template-generator</code> 空文件夹，作为整个项目的根目录，后续各阶段的项目和目录都放到它之下。<br>这样做还有一个好处，就是让不同项目模块可以用 相对路径 寻找文件，便于整个项目的开源共享。<br>建议大家养成习惯，使用 Git 来管理项目。如果使用 IDEA 开发工具来创建新项目，可以直接勾选 Create Git repository ，工具会自动帮你初始化项目为 Git 仓库。</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114130738168-1948313359.png" alt="image-20231114130738776"></p>
<p>当然，也可以进入项目根目录，执行 <code>git init</code> 命令创建 Git 仓库。</p>
<h3 id="2、创建忽略文件"><a href="#2、创建忽略文件" class="headerlink" title="2、创建忽略文件"></a>2、创建忽略文件</h3><p>创建好新项目后，使用 IDEA 开发工具打开项目，进入底部的 <code>Git </code>标签，会发现很多和项目无关的 IDEA 自动生成的工程文件被添加到了 Git 托管。</p>
<p>新初始化的项目没有提交记录，可以点击<code>Commit local changes</code> </p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114131047442-100033204.png" alt="image-20231114131048121"></p>
<p>或者直接点击侧边栏<code>Commit</code>选项</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114131347111-1875962650.png" alt="image-20231114131347901"></p>
<p>我们不希望提交这些没有意义的文件，所以需要使用 <code>.gitignore </code>文件来忽略这些文件，不让它们被 Git 托管。<br>那么如何编写<code> .gitignore</code> 文件呢？</p>
<p>其实这个忽略文件没必要自己写，我们可以在 IDEA 的 Settings &#x3D;&gt; Plugins 中搜索 <code>.ignore</code> 插件并安装：</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114132121843-1779918185.png" alt="image-20231114132122606"></p>
<p>如果网络或其他原因导致搜索不出来，可以到<a target="_blank" rel="noopener" href="https://plugins.jetbrains.com/plugin/7495--ignore">官方插件市场</a>下载到本地采用从磁盘安装的方式</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114132339542-1331521183.png" alt="image-20231114132340104"></p>
<p>然后在项目根目录处选中右键，使用 .ignore 插件创建 .gitignore 文件：</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114133121968-2061017438.png" alt="image-20231114133122575"></p>
<p>可以在搜索框中搜索需要的忽略类型，比如<code>JetBrains</code>、<code>Java</code>、<code>Maven</code>等</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114133348523-2117359186.png" alt="image-20231114133349201"></p>
<p>IDEA询问是否将该文件添加到版本库，添加即可</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114133714418-843339042.png" alt="image-20231114133715188"></p>
<p>也可以添加一些自定义忽略文件或目录</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231120221518424-682582666.png" alt="image-20231120221517691"></p>
<p>但是，即使有些文件已经添加到了<code> .gitignore</code> 文件中，在 IDEA 中显示的还是绿色（已被 Git 托管）状态</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231120222021476-30701430.png" alt="image-20231120222021082"></p>
<p>这是因为这些文件已经被 Git 跟踪。而<code>.gitignore</code> 文件仅影响未跟踪的文件</p>
<p>如果文件已经被 Git 跟踪，那么 <code>.gitignore</code> 文件对它们没有影响<br>所以我们需要打开终端，在项目根目录下执行如下命令，取消 Git 跟踪</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">rm</span> -rf --cached .</span><br></pre></td></tr></table></figure>

<p>执行效果如下</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231120222151167-1504539761.png" alt="image-20231120222150842"></p>
<p>将文件重新添加到暂存区、例如将刚才创建的<code>.gitignore</code>添加到暂存区</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231120222407576-1192476449.png" alt="image-20231120222407201"></p>
<h3 id="3、创建-Demo-示例代码工程"><a href="#3、创建-Demo-示例代码工程" class="headerlink" title="3、创建 Demo 示例代码工程"></a>3、创建 Demo 示例代码工程</h3><p>为了制作代码生成器，我们需要一些示例模板代码，后续会基于这些模板代码来定制生成。<br>比如第一阶段，我们会用到一套鱼皮提前编写好的 ACM 示例模板代码，从而制作定制化 ACM 模板代码生成器</p>
<p>在第二阶段，我们会用到一套 Spring Boot 初始化项目模板。<br>让我们新建一个 <code>shiguang-generator-demo-projects</code> 目录，统一存放所有的示例代码，然后将鱼皮准备的 ACM 模板项目（acm-template）复制到该目录下。</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231120223611034-832583174.png" alt="image-20231120223610559"></p>
<h4 id="ACM-示例代码模板介绍"><a href="#ACM-示例代码模板介绍" class="headerlink" title="ACM 示例代码模板介绍"></a>ACM 示例代码模板介绍</h4><p>鱼皮准备的 ACM 示例代码模板非常简单，只是一个干净的 Java 项目，没有使用 Maven 和任何第三方依赖<br>结构如下，核心组成是静态文件 <code>README.md</code> 和代码文件 <code>MainTemplate</code></p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231120223903675-2081076447.png" alt="image-20231120223902936"></p>
<p><code>README.md</code>内容如图，仅包含了简单的描述文本</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231120223952403-971394141.png" alt="image-20231120223952121"></p>
<p><code>MainTemplate.java</code> 是一段 ACM 示例输入代码，作用是计算并输出多数之和</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.shiguang.acm;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.Scanner;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * ACM 输入模板（多数之和）</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MainTemplate</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">Scanner</span> <span class="variable">scanner</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Scanner</span>(System.in);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">while</span> (scanner.hasNext()) &#123;</span><br><span class="line">            <span class="comment">// 读取输入元素个数</span></span><br><span class="line">            <span class="type">int</span> <span class="variable">n</span> <span class="operator">=</span> scanner.nextInt();</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 读取数组</span></span><br><span class="line">            <span class="type">int</span>[] arr = <span class="keyword">new</span> <span class="title class_">int</span>[n];</span><br><span class="line">            <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; n; i++) &#123;</span><br><span class="line">                arr[i] = scanner.nextInt();</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 处理问题逻辑，根据需要进行输出</span></span><br><span class="line">            <span class="comment">// 示例：计算数组元素的和</span></span><br><span class="line">            <span class="type">int</span> <span class="variable">sum</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line">            <span class="keyword">for</span> (<span class="type">int</span> num : arr) &#123;</span><br><span class="line">                sum += num;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            System.out.println(<span class="string">&quot;Sum: &quot;</span> + sum);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        scanner.close();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>在第一阶段的教程中，我们将改造这个 Java 代码文件，让它能同时支持多种不同的输入方式</p>
<h3 id="4、创建本地代码生成器项目"><a href="#4、创建本地代码生成器项目" class="headerlink" title="4、创建本地代码生成器项目"></a>4、创建本地代码生成器项目</h3><p>使用 IDEA 开发工具，在项目根目录中新建工程，创建 yuzi-generator-basic 项目。需要注意以下几点：</p>
<ol>
<li>项目存放位置在 <code>template_generator </code>根目录下</li>
<li>取消 Git 仓库勾选（因为已经在外层进行 Git 托管）</li>
<li>使用 Maven 管理项目</li>
<li>JDK 选择 1.8！不要追求新版本</li>
<li>高级设置中，指定 GroupId 和 ArtifactId</li>
</ol>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231120224816678-1665314943.png" alt="image-20231120224815563"></p>
 
      <!-- reward -->
      
    </div>
    

    <!-- copyright -->
    
    <footer class="article-footer">
       
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/%E5%AD%A6%E4%B9%A0/" rel="tag">学习</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/%E9%A1%B9%E7%9B%AE/" rel="tag">项目</a></li></ul>

    </footer>
  </div>

    
 
   
  
</article>

    
    <article
  id="post-定制化代码生成项目-day1"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2023/11/13/%E5%AE%9A%E5%88%B6%E5%8C%96%E4%BB%A3%E7%A0%81%E7%94%9F%E6%88%90%E9%A1%B9%E7%9B%AE-day1/"
    >定制化代码生成项目_day1</a> 
</h2>
 

      
    </header>
     
    <div class="article-meta">
      <a href="/2023/11/13/%E5%AE%9A%E5%88%B6%E5%8C%96%E4%BB%A3%E7%A0%81%E7%94%9F%E6%88%90%E9%A1%B9%E7%9B%AE-day1/" class="article-date">
  <time datetime="2023-11-13T15:49:02.000Z" itemprop="datePublished">2023-11-13</time>
</a> 
  <div class="article-category">
    <a class="article-category-link" href="/categories/%E9%A1%B9%E7%9B%AE%E7%AC%94%E8%AE%B0/">项目笔记</a>
  </div>
   
    </div>
      
    <div class="article-entry" itemprop="articleBody">
       
  <h2 id="需求分析"><a href="#需求分析" class="headerlink" title="需求分析"></a>需求分析</h2><p>其实上面已经带大家了解了项目的基本信息、项目的意义和价值。在需求分析阶段，我们通常还要进行一些调研工作，帮助我们明确需求、为后面的设计做好充分的准备。</p>
<h3 id="调研"><a href="#调研" class="headerlink" title="调研"></a>调研</h3><p>网上有一些代码生成器项目，比如前端 <a target="_blank" rel="noopener" href="https://pro.ant.design/zh-CN">Ant Design Pro</a> 中后台项目脚手架，能够让用户交互式地创建指定的项目；还有后端 MyBatis X 插件，能够让用户通过界面来创建 CRUD 重复代码。但这些项目都是开发者提前制作好了代码生成器，然后让你 根据他们设置好的规则 生成代码（或者拉取特定位置的代码），生成后的代码通常还要再自己二次修改，不够灵活。</p>
<p>还有很多所谓的代码生成项目，其实本质上是一个现成的项目模板，让你通过编写对应的配置文件来使用项目，或者还是基于预设的程序来生成特定代码。比如 <a target="_blank" rel="noopener" href="https://yuyuanweb.feishu.cn/wiki/VC1qwmX9diCBK3kidyec74vFnde">编程导航知识星球</a> 的 Spring Boot 万用项目模板，或者网上很多知名的开源管理系统。</p>
<p>这和我们要做的事情不同，我们的目标是升级一个层次！打造一个帮助大家快速制作代码生成器的工具，也就是 “造轮子的轮子”。</p>
<p>然后再升级一个层次！允许用户像发布应用一样，在平台上发布和管理代码生成器，便于共享和协作！</p>
<h2 id="技术选型"><a href="#技术选型" class="headerlink" title="技术选型"></a>技术选型</h2><p>暂定的核心技术如下，实际开发中还会引入新技术</p>
<h3 id="前端"><a href="#前端" class="headerlink" title="前端"></a>前端</h3><ul>
<li>React 开发框架 + 组件库 + 代码编辑器</li>
<li>前端工程化：ESLint + Prettier + TypeScript</li>
</ul>
<h3 id="后端"><a href="#后端" class="headerlink" title="后端"></a>后端</h3><ul>
<li>Java Spring Boot + MySQL + MyBatis Plus（万用后端模板）</li>
<li>Java 命令行应用开发</li>
<li>FreeMarker 模板引擎</li>
<li>Vert.x 响应式编程</li>
<li>Caffeine + Redis 多级缓存</li>
<li>分布式任务调度系统</li>
<li>多种设计模式</li>
<li>多种系统设计的巧思</li>
<li>对象存储、</li>
</ul>
<h3 id="学习重点"><a href="#学习重点" class="headerlink" title="学习重点"></a>学习重点</h3><p>其中：Java 命令行应用开发、FreeMarker 模板引擎、Vert.x 响应式编程、设计模式、系统设计的巧思、分布式任务调度系统都是本项目的学习重点，也是校招简历上很少有同学提到的知识实践，学完后能够大大增加简历的区分度！<br>比如 Vert.x 框架，并发连接处理能力吊打 Spring 几条街！</p>
<blockquote>
<p>Web Framework Benchmarks 性能对比网站：</p>
<p><a target="_blank" rel="noopener" href="https://www.techempower.com/benchmarks/#section=data-r21&test=composite">https://www.techempower.com/benchmarks/#section=data-r21&amp;test=composite</a></p>
</blockquote>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231113235845631-1230764903.png" alt="image-20231113235845853"></p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231113235911990-217135334.png" alt="image-20231113235912317"></p>
<h2 id="项目设计"><a href="#项目设计" class="headerlink" title="项目设计"></a>项目设计</h2><p>首先我们要理解代码生成的核心原理。</p>
<h3 id="代码生成器的核心原理"><a href="#代码生成器的核心原理" class="headerlink" title="代码生成器的核心原理"></a>代码生成器的核心原理</h3><p>一句话：参数 + 模板文件 &#x3D; 生成的完整代码</p>
<p>比如参数：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">作者 = 鱼皮</span><br></pre></td></tr></table></figure>

<p>模板文件代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">-----------</span><br><span class="line">我是 $&#123;作者&#125;</span><br><span class="line">-----------</span><br></pre></td></tr></table></figure>

<p>将参数注入到模板文件中，得到生成的完整代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">-----------</span><br><span class="line">我是 鱼皮</span><br><span class="line">-----------</span><br></pre></td></tr></table></figure>

<p>如果想要使用这套模板生成其他的代码，只需要改变参数的值即可，而不需要改变模板文件。<br>理解了代码生成器的核心原理后，<strong>就可以开始思考项目的设计实现方案了</strong>。</p>
<p>项目总共分为 3 个阶段，让我们分别来进行设计。</p>
<h3 id="第一阶段-本地代码生成器"><a href="#第一阶段-本地代码生成器" class="headerlink" title="第一阶段 - 本地代码生成器"></a>第一阶段 - 本地代码生成器</h3><p>这个阶段，我们的目标是做一个本地（离线）的代码生成器，实现一个简易的 Java ACM 模板项目的定制化生成。<br>本阶段不依赖复杂的开发框架，没学过任何开发框架也能学习。</p>
<h4 id="业务流程"><a href="#业务流程" class="headerlink" title="业务流程"></a>业务流程</h4><ol>
<li>准备用于制作代码生成器的原始代码（比如 Java ACM 模板项目），用于后续生成</li>
<li>开发者基于原始代码，设置参数、编写动态模板</li>
<li>制作可交互的命令行工具，支持用户输入参数，得到代码生成器 jar 包</li>
<li>使用者得到代码生成器 jar 包，执行程序并输入参数，从而生成完整代码</li>
</ol>
<p>流程图如下：</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114000342604-1915294376.png" alt="image-20231114000342815"></p>
<h4 id="实现思路"><a href="#实现思路" class="headerlink" title="实现思路"></a>实现思路</h4><ol>
<li>先根据本地项目，扫描文件树，实现同样的静态代码生成</li>
<li>根据本地的项目，预设部分动态参数、编写模板文件，能够传入配置对象进行生成</li>
<li>制作可交互的命令行工具，接受用户输入的参数，并动态生成代码</li>
<li>封装制作代码生成器 jar 包文件，并简化使用命令</li>
</ol>
<h3 id="第二阶段-代码生成器制作工具"><a href="#第二阶段-代码生成器制作工具" class="headerlink" title="第二阶段 - 代码生成器制作工具"></a>第二阶段 - 代码生成器制作工具</h3><p>这个阶段，我们的目标是做一个本地的代码生成器制作工具，能够快速将一个项目制作为可以动态定制部分内容的代码生成器。并且以一个 Spring Boot 初始化项目模板（Maven 项目）为例，演示如何根据自己的需要动态生成 Java 后端初始化项目。<br>本阶段的学习需要一定的 Spring Boot 开发知识，最好先完成 <a target="_blank" rel="noopener" href="https://yuyuanweb.feishu.cn/wiki/SePYwTc9tipQiCktw7Uc7kujnCd">星球的其他项目</a> ，推荐用户中心和聚合搜索。</p>
<h4 id="业务流程-1"><a href="#业务流程-1" class="headerlink" title="业务流程"></a>业务流程</h4><ol>
<li>准备用于制作代码生成器的原始代码（比如 Spring Boot 项目模板），用于后续生成</li>
<li>开发者基于原始代码，使用代码生成器制作工具，来快速设置参数、生成动态模板</li>
<li>使用代码生成器制作工具，动态生成代码生成器 jar 包</li>
<li>使用者得到代码生成器 jar 包，执行程序并输入参数，从而生成完整代码</li>
</ol>
<p>流程图如下：</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114000637601-264962715.png" alt="image-20231114000638094"></p>
<h4 id="实现思路-1"><a href="#实现思路-1" class="headerlink" title="实现思路"></a>实现思路</h4><ol>
<li>使用独立空间来存储管理要生成的原始文件、动态模板文件等</li>
<li>使用配置文件来记录要生成的参数和模板文件信息、自定义配置等 元信息</li>
<li>代码生成器制作工具需要有多种可单独或组合使用的功能，比如从原始文件中抽取参数、动态生成命令行工具、打 jar 包等</li>
</ol>
<h4 id="关键问题"><a href="#关键问题" class="headerlink" title="关键问题"></a>关键问题</h4><ol>
<li>如何使用配置文件来记录参数和模板文件信息？何种结构？</li>
<li>怎么能够提高代码生成器的制作效率？工具应该提供哪些能力？</li>
<li>如何从原始文件中抽取参数？有哪些类型的参数？有哪些抽取规则？比如布尔类型参数（是否生成）、字符串类型参数（生成指定的值）等</li>
</ol>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114000807799-1482793121.png" alt="image-20231114000808254"></p>
<ol start="4">
<li>如何动态生成配置类？如何动态生成命令行工具？如何动态打 jar 包？</li>
</ol>
<h3 id="第三阶段-在线代码生成器平台"><a href="#第三阶段-在线代码生成器平台" class="headerlink" title="第三阶段 - 在线代码生成器平台"></a>第三阶段 - 在线代码生成器平台</h3><p>经过前两个阶段，我们已经能够使用本地的代码生成器制作工具来快速定制自己的代码生成器了。<br>但如果我们想和团队其他同学共同维护代码生成器、或者使用其他人的代码生成器，通过本地文件互传的方式肯定就很麻烦了。<br>所以本阶段我们要打造一个在线代码生成器平台，可以理解为代码生成器的 应用市场。所有人都能发布、使用、甚至是在线制作自己的代码生成器！<br>本阶段我们的终极目标是，在平台上制作和发布项目 “换皮” 工具，帮助小伙伴们一键给网络热门项目换皮！</p>
<h4 id="业务流程-2"><a href="#业务流程-2" class="headerlink" title="业务流程"></a>业务流程</h4><ol>
<li>获取用于制作代码生成器的原始代码（手动准备或者远程拉取代码）</li>
<li>开发者基于原始代码，使用 在线代码生成器制作工具，来快速制作代码生成器</li>
<li>开发者发布代码生成器至平台</li>
<li>使用者在平台上搜索代码生成器，支持在线使用或者下载离线 jar 包（甚至还可以支持接口调用）、</li>
</ol>
<p>完整业务流程图如下：</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231114001035459-979742453.png" alt="image-20231114001035892"></p>
<h4 id="实现思路-2"><a href="#实现思路-2" class="headerlink" title="实现思路"></a>实现思路</h4><ol>
<li>使用 Web 开发框架实现代码生成器信息的增删改查</li>
<li>将本地的配置和文件 上云，存储到数据库、对象存储等云服务。</li>
<li>通过可视化界面来操作第二阶段的代码生成器制作工具，复用阶段二的成果。</li>
</ol>
<h4 id="关键问题-1"><a href="#关键问题-1" class="headerlink" title="关键问题"></a>关键问题</h4><ol>
<li>怎么在云上存储管理代码生成器？</li>
<li>如何通过前端开发，提高代码生成器的制作效率？</li>
<li>如何通过后端优化，提高代码生成器的制作性能？</li>
<li>如何保证代码生成器的存储空间不超限、如何优化存储？</li>
</ol>
<h2 id="新建代码仓库"><a href="#新建代码仓库" class="headerlink" title="新建代码仓库"></a>新建代码仓库</h2><blockquote>
<p>搭建仓库，点 star 的都是精神股东</p>
</blockquote>
<p>鱼皮仓库：<a target="_blank" rel="noopener" href="https://github.com/liyupi/yuzi-generator">https://github.com/liyupi/yuzi-generator</a></p>
<p>我的仓库：<a target="_blank" rel="noopener" href="https://github.com/Shiguang-coding/template-generator">https://github.com/Shiguang-coding/template-generator</a></p>
<h2 id="本期作业"><a href="#本期作业" class="headerlink" title="本期作业"></a>本期作业</h2><ol>
<li>理解代码生成器项目三个阶段的区别，从中学习到拆解项目的思路和方法</li>
<li>尝试自己做项目时，像鱼皮本篇教程一样编写一个项目设计方案</li>
<li>思考上述关键问题的实现方案，欢迎大家交流讨论</li>
<li>在 GitHub 新建仓库（或者 fork 鱼皮的代码仓库），为下期项目开发做准备</li>
</ol>
 
      <!-- reward -->
      
    </div>
    

    <!-- copyright -->
    
    <footer class="article-footer">
       
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/%E5%AD%A6%E4%B9%A0/" rel="tag">学习</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/%E9%A1%B9%E7%9B%AE/" rel="tag">项目</a></li></ul>

    </footer>
  </div>

    
 
   
  
</article>

    
    <article
  id="post-定制化代码生成项目"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2023/11/13/%E5%AE%9A%E5%88%B6%E5%8C%96%E4%BB%A3%E7%A0%81%E7%94%9F%E6%88%90%E9%A1%B9%E7%9B%AE/"
    >定制化代码生成项目</a> 
</h2>
 

      
    </header>
     
    <div class="article-meta">
      <a href="/2023/11/13/%E5%AE%9A%E5%88%B6%E5%8C%96%E4%BB%A3%E7%A0%81%E7%94%9F%E6%88%90%E9%A1%B9%E7%9B%AE/" class="article-date">
  <time datetime="2023-11-13T15:32:48.000Z" itemprop="datePublished">2023-11-13</time>
</a> 
  <div class="article-category">
    <a class="article-category-link" href="/categories/%E9%A1%B9%E7%9B%AE%E7%AC%94%E8%AE%B0/">项目笔记</a>
  </div>
   
    </div>
      
    <div class="article-entry" itemprop="articleBody">
       
  <h2 id="项目介绍"><a href="#项目介绍" class="headerlink" title="项目介绍"></a><strong>项目介绍</strong></h2><p>基于 React + Spring Boot + Vert.x 响应式编程的 定制化代码生成项目 。 注意！这次的项目会很特别，听起来是一个项目，但其实是循序渐进的 <strong>3 个项目</strong> ！</p>
<p>第一阶段，我会带大家制作属于自己的 本地代码生成器 ，是一个 <strong>基于命令行的脚手架</strong> ，能够根据用户的交互式输入快速生成特定代码。</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231113234134736-904582628.png" alt="image-20231113234135027"></p>
<p>网上绝大多数的教程，也只是讲到这个阶段。 第二阶段，让我们上升一个层次，带大家开发 制作代码生成器的工具 。比如你有一段常用的项目代码，使用该工具，可以快速把项目代码制作为代码生成器，将是提高工作效率的大杀器！ 第三阶段，让我们再上升一个层次，带大家开发 在线代码生成器平台 ！你可以在平台上制作发布自己的代码生成器，还可以在线使用别人的代码生成器，甚至可以共享协作！</p>
<p><img src="https://img2023.cnblogs.com/blog/2233039/202311/2233039-20231113234148551-86739101.png" alt="image-20231113234148992"></p>
<p>之所以要分阶段，一方面是因为项目是比较庞大的，拆分后学习会更轻松；另一方面是不同阶段的难度不同，大家可以独立学习。 比如哪怕你什么框架都没学过，也可以完成第一阶段；而如果你学过开发框架，可以完成第二阶段；如果你想学习更多高级知识和优化技巧，再去看第三阶段。够贴心</p>
<h2 id="为什么做这个项目"><a href="#为什么做这个项目" class="headerlink" title="为什么做这个项目"></a>为什么做这个项目</h2><ol>
<li>教程资料少：网上虽然有现成的项目模板，但基本都是别人封装好的，只能按作者的要求生成，并且缺少项目教程；而本项目不仅带大家做自己的代码生成器，还会进 2 步扩展，打造制作自定义代码生成器的工具和平台。</li>
<li>新颖且亮眼：别人写代码，你做生产代码的脚手架、工具和平台来提高研发效能，降维打击。</li>
<li>能学到东西：不再是增删改查的项目，而是包含了大量的实际业务场景、系统设计和解决方案。</li>
<li>有区分度：区别于传统 Web 应用，项目涉及命令行应用、响应式编程、性能优化的入门及实战，给你的简历增加竞争力。</li>
</ol>
<h2 id="技术选型"><a href="#技术选型" class="headerlink" title="技术选型"></a>技术选型</h2><p>暂定的核心技术如下，实际开发中还会引入新技术 <strong>前端</strong></p>
<ul>
<li>React 开发框架 + 组件库 + 代码编辑器</li>
<li>前端工程化：ESLint + Prettier + TypeScript <strong>后端</strong></li>
<li>Java Spring Boot + MySQL + MyBatis Plus（万用后端模板）</li>
<li>Java 命令行应用开发</li>
<li>FreeMarker 模板引擎、</li>
<li>Vert.x 响应式编程</li>
<li>Caffeine + Redis 多级缓存、</li>
<li>分布式任务调度系统</li>
<li>多种设计模式</li>
<li>多种系统设计的巧思</li>
<li>对象存储</li>
</ul>
 
      <!-- reward -->
      
    </div>
    

    <!-- copyright -->
    
    <footer class="article-footer">
       
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/%E5%AD%A6%E4%B9%A0/" rel="tag">学习</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/%E9%A1%B9%E7%9B%AE/" rel="tag">项目</a></li></ul>

    </footer>
  </div>

    
 
   
  
</article>

    
  </article>
  

  
  <nav class="page-nav">
    
    <a class="extend prev" rel="prev" href="/page/2/">上一页</a><a class="page-number" href="/">1</a><a class="page-number" href="/page/2/">2</a><span class="page-number current">3</span><a class="page-number" href="/page/4/">4</a><a class="page-number" href="/page/5/">5</a><span class="space">&hellip;</span><a class="page-number" href="/page/8/">8</a><a class="extend next" rel="next" href="/page/4/">下一页</a>
  </nav>
  
</section>
</div>

      <footer class="footer">
  <div class="outer">
    <ul>
      <li>
        Copyrights &copy;
        2023
        <i class="ri-heart-fill heart_icon"></i> Shiguang
      </li>
    </ul>
    <ul>
      <li>
        
      </li>
    </ul>
    <ul>
      <li>
        
        
        <span>
  <span><i class="ri-user-3-fill"></i>Visitors:<span id="busuanzi_value_site_uv"></span></span>
  <span class="division">|</span>
  <span><i class="ri-eye-fill"></i>Views:<span id="busuanzi_value_page_pv"></span></span>
</span>
        
      </li>
    </ul>
    <ul>
      
    </ul>
    <ul>
      
    </ul>
    <ul>
      <li>
        <!-- cnzz统计 -->
        
        <script type="text/javascript" src='https://s9.cnzz.com/z_stat.php?id=1278069914&amp;web_id=1278069914'></script>
        
      </li>
    </ul>
  </div>
</footer>    
    </main>
    <div class="float_btns">
      <div class="totop" id="totop">
  <i class="ri-arrow-up-line"></i>
</div>

<div class="todark" id="todark">
  <i class="ri-moon-line"></i>
</div>

    </div>
    <aside class="sidebar on">
      <button class="navbar-toggle"></button>
<nav class="navbar">
  
  <div class="logo">
    <a href="/"><img src="/images/ayer-side.svg" alt="時光"></a>
  </div>
  
  <ul class="nav nav-main">
    
    <li class="nav-item">
      <a class="nav-item-link" href="/">主页</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/archives">归档</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/categories">分类</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags">标签</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/friends">友链</a>
    </li>
    
  </ul>
</nav>
<nav class="navbar navbar-bottom">
  <ul class="nav">
    <li class="nav-item">
      
      <a class="nav-item-link nav-item-search"  title="Search">
        <i class="ri-search-line"></i>
      </a>
      
      
      <a class="nav-item-link" target="_blank" href="/atom.xml" title="RSS Feed">
        <i class="ri-rss-line"></i>
      </a>
      
    </li>
  </ul>
</nav>
<div class="search-form-wrap">
  <div class="local-search local-search-plugin">
  <input type="search" id="local-search-input" class="local-search-input" placeholder="Search...">
  <div id="local-search-result" class="local-search-result"></div>
</div>
</div>
    </aside>
    <div id="mask"></div>

<!-- #reward -->
<div id="reward">
  <span class="close"><i class="ri-close-line"></i></span>
  <p class="reward-p"><i class="ri-cup-line"></i>请我喝杯咖啡吧~</p>
  <div class="reward-box">
    
    <div class="reward-item">
      <img class="reward-img" src="/images/alipay.jpg">
      <span class="reward-type">支付宝</span>
    </div>
    
    
    <div class="reward-item">
      <img class="reward-img" src="/images/wechat.jpg">
      <span class="reward-type">微信</span>
    </div>
    
  </div>
</div>
    
<script src="/js/jquery-3.6.0.min.js"></script>
 
<script src="/js/lazyload.min.js"></script>

<!-- Tocbot -->

<script src="https://cdn.staticfile.org/jquery-modal/0.9.2/jquery.modal.min.js"></script>
<link
  rel="stylesheet"
  href="https://cdn.staticfile.org/jquery-modal/0.9.2/jquery.modal.min.css"
/>
<script src="https://cdn.staticfile.org/justifiedGallery/3.8.1/js/jquery.justifiedGallery.min.js"></script>

<script src="/dist/main.js"></script>

<!-- ImageViewer -->
 <!-- Root element of PhotoSwipe. Must have class pswp. -->
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">

    <!-- Background of PhotoSwipe. 
         It's a separate element as animating opacity is faster than rgba(). -->
    <div class="pswp__bg"></div>

    <!-- Slides wrapper with overflow:hidden. -->
    <div class="pswp__scroll-wrap">

        <!-- Container that holds slides. 
            PhotoSwipe keeps only 3 of them in the DOM to save memory.
            Don't modify these 3 pswp__item elements, data is added later on. -->
        <div class="pswp__container">
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
        </div>

        <!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
        <div class="pswp__ui pswp__ui--hidden">

            <div class="pswp__top-bar">

                <!--  Controls are self-explanatory. Order can be changed. -->

                <div class="pswp__counter"></div>

                <button class="pswp__button pswp__button--close" title="Close (Esc)"></button>

                <button class="pswp__button pswp__button--share" style="display:none" title="Share"></button>

                <button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>

                <button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>

                <!-- Preloader demo http://codepen.io/dimsemenov/pen/yyBWoR -->
                <!-- element will get class pswp__preloader--active when preloader is running -->
                <div class="pswp__preloader">
                    <div class="pswp__preloader__icn">
                        <div class="pswp__preloader__cut">
                            <div class="pswp__preloader__donut"></div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
                <div class="pswp__share-tooltip"></div>
            </div>

            <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
            </button>

            <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
            </button>

            <div class="pswp__caption">
                <div class="pswp__caption__center"></div>
            </div>

        </div>

    </div>

</div>

<link rel="stylesheet" href="https://cdn.staticfile.org/photoswipe/4.1.3/photoswipe.min.css">
<link rel="stylesheet" href="https://cdn.staticfile.org/photoswipe/4.1.3/default-skin/default-skin.min.css">
<script src="https://cdn.staticfile.org/photoswipe/4.1.3/photoswipe.min.js"></script>
<script src="https://cdn.staticfile.org/photoswipe/4.1.3/photoswipe-ui-default.min.js"></script>

<script>
    function viewer_init() {
        let pswpElement = document.querySelectorAll('.pswp')[0];
        let $imgArr = document.querySelectorAll(('.article-entry img:not(.reward-img)'))

        $imgArr.forEach(($em, i) => {
            $em.onclick = () => {
                // slider展开状态
                // todo: 这样不好，后面改成状态
                if (document.querySelector('.left-col.show')) return
                let items = []
                $imgArr.forEach(($em2, i2) => {
                    let img = $em2.getAttribute('data-idx', i2)
                    let src = $em2.getAttribute('data-target') || $em2.getAttribute('src')
                    let title = $em2.getAttribute('alt')
                    // 获得原图尺寸
                    const image = new Image()
                    image.src = src
                    items.push({
                        src: src,
                        w: image.width || $em2.width,
                        h: image.height || $em2.height,
                        title: title
                    })
                })
                var gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, items, {
                    index: parseInt(i)
                });
                gallery.init()
            }
        })
    }
    viewer_init()
</script> 
<!-- MathJax -->

<!-- Katex -->

<!-- busuanzi  -->
 
<script src="/js/busuanzi-2.3.pure.min.js"></script>
 
<!-- ClickLove -->

<!-- ClickBoom1 -->

<!-- ClickBoom2 -->

<!-- CodeCopy -->
 
<link rel="stylesheet" href="/css/clipboard.css">
 <script src="https://cdn.staticfile.org/clipboard.js/2.0.10/clipboard.min.js"></script>
<script>
  function wait(callback, seconds) {
    var timelag = null;
    timelag = window.setTimeout(callback, seconds);
  }
  !function (e, t, a) {
    var initCopyCode = function(){
      var copyHtml = '';
      copyHtml += '<button class="btn-copy" data-clipboard-snippet="">';
      copyHtml += '<i class="ri-file-copy-2-line"></i><span>COPY</span>';
      copyHtml += '</button>';
      $(".highlight .code pre").before(copyHtml);
      $(".article pre code").before(copyHtml);
      var clipboard = new ClipboardJS('.btn-copy', {
        target: function(trigger) {
          return trigger.nextElementSibling;
        }
      });
      clipboard.on('success', function(e) {
        let $btn = $(e.trigger);
        $btn.addClass('copied');
        let $icon = $($btn.find('i'));
        $icon.removeClass('ri-file-copy-2-line');
        $icon.addClass('ri-checkbox-circle-line');
        let $span = $($btn.find('span'));
        $span[0].innerText = 'COPIED';
        
        wait(function () { // 等待两秒钟后恢复
          $icon.removeClass('ri-checkbox-circle-line');
          $icon.addClass('ri-file-copy-2-line');
          $span[0].innerText = 'COPY';
        }, 2000);
      });
      clipboard.on('error', function(e) {
        e.clearSelection();
        let $btn = $(e.trigger);
        $btn.addClass('copy-failed');
        let $icon = $($btn.find('i'));
        $icon.removeClass('ri-file-copy-2-line');
        $icon.addClass('ri-time-line');
        let $span = $($btn.find('span'));
        $span[0].innerText = 'COPY FAILED';
        
        wait(function () { // 等待两秒钟后恢复
          $icon.removeClass('ri-time-line');
          $icon.addClass('ri-file-copy-2-line');
          $span[0].innerText = 'COPY';
        }, 2000);
      });
    }
    initCopyCode();
  }(window, document);
</script>
 
<!-- CanvasBackground -->

<script>
  if (window.mermaid) {
    mermaid.initialize({ theme: "forest" });
  }
</script>


    
    

  </div>
</body>

</html>